Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp @ 1

Last change on this file since 1 was 1, checked in by landauf, 17 years ago
File size: 120.9 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreD3D9RenderSystem.h"
30#include "OgreD3D9Prerequisites.h"
31#include "OgreD3D9DriverList.h"
32#include "OgreD3D9Driver.h"
33#include "OgreD3D9VideoModeList.h"
34#include "OgreD3D9VideoMode.h"
35#include "OgreD3D9RenderWindow.h"
36#include "OgreD3D9TextureManager.h"
37#include "OgreD3D9Texture.h"
38#include "OgreLogManager.h"
39#include "OgreLight.h"
40#include "OgreMath.h"
41#include "OgreD3D9HardwareBufferManager.h"
42#include "OgreD3D9HardwareIndexBuffer.h"
43#include "OgreD3D9HardwareVertexBuffer.h"
44#include "OgreD3D9VertexDeclaration.h"
45#include "OgreD3D9GpuProgram.h"
46#include "OgreD3D9GpuProgramManager.h"
47#include "OgreD3D9HLSLProgramFactory.h"
48#include "OgreHighLevelGpuProgramManager.h"
49#include "OgreD3D9HardwareOcclusionQuery.h"
50#include "OgreFrustum.h"
51#include "OgreD3D9MultiRenderTarget.h"
52
53#define FLOAT2DWORD(f) *((DWORD*)&f)
54
55namespace Ogre
56{
57
58        //---------------------------------------------------------------------
59        D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance )
60        {
61                LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " created." );
62
63                // set the instance being passed
64                mhInstance = hInstance;
65
66                // set pointers to NULL
67                mpD3D = NULL;
68                mpD3DDevice = NULL;
69                mDriverList = NULL;
70                mActiveD3DDriver = NULL;
71        mTextureManager = NULL;
72        mHardwareBufferManager = NULL;
73                mGpuProgramManager = NULL;
74                mPrimaryWindow = NULL;
75                mDeviceLost = false;
76                mBasicStatesInitialised = false;
77                mUseNVPerfHUD = false;
78        mHLSLProgramFactory = NULL;
79
80                // init lights
81                for(int i = 0; i < MAX_LIGHTS; i++ )
82                        mLights[i] = 0;
83
84                // Create our Direct3D object
85                if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
86                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" );
87
88                // set config options defaults
89                initConfigOptions();
90
91                // fsaa options
92                mFSAAType = D3DMULTISAMPLE_NONE;
93                mFSAAQuality = 0;
94
95                // set stages desc. to defaults
96                for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++)
97                {
98                        mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
99                        mTexStageDesc[n].coordIndex = 0;
100                        mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
101                        mTexStageDesc[n].pTex = 0;
102                        mTexStageDesc[n].pVertexTex = 0;
103                }
104
105                mLastVertexSourceCount = 0;
106
107        mCurrentLights = 0;
108
109                // Enumerate events
110                mEventNames.push_back("DeviceLost");
111                mEventNames.push_back("DeviceRestored");
112
113
114        }
115        //---------------------------------------------------------------------
116        D3D9RenderSystem::~D3D9RenderSystem()
117        {
118        shutdown();
119
120        // Deleting the HLSL program factory
121        if (mHLSLProgramFactory)
122        {
123            // Remove from manager safely
124            if (HighLevelGpuProgramManager::getSingletonPtr())
125                HighLevelGpuProgramManager::getSingleton().removeFactory(mHLSLProgramFactory);
126            delete mHLSLProgramFactory;
127            mHLSLProgramFactory = 0;
128        }
129
130                SAFE_RELEASE( mpD3D );
131
132                LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " destroyed." );
133        }
134        //---------------------------------------------------------------------
135        const String& D3D9RenderSystem::getName() const
136        {
137                static String strName( "Direct3D9 Rendering Subsystem");
138                return strName;
139        }
140        //---------------------------------------------------------------------
141        D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers()
142        {
143                if( !mDriverList )
144                        mDriverList = new D3D9DriverList( mpD3D );
145
146                return mDriverList;
147        }
148        //---------------------------------------------------------------------
149        bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
150        {
151                HRESULT hr;
152                hr = mpD3D->CheckDeviceMultiSampleType( 
153                                adapterNum, 
154                                deviceType, 
155                                format, 
156                                fullScreen, 
157                                type, 
158                                outQuality);
159
160                if (SUCCEEDED(hr))
161                        return true;
162                else
163                        return false;
164        }
165        //---------------------------------------------------------------------
166        void D3D9RenderSystem::initConfigOptions()
167        {
168                D3D9DriverList* driverList;
169                D3D9Driver* driver;
170
171                ConfigOption optDevice;
172                ConfigOption optVideoMode;
173                ConfigOption optFullScreen;
174                ConfigOption optVSync;
175                ConfigOption optAA;
176                ConfigOption optFPUMode;
177                ConfigOption optNVPerfHUD;
178
179                driverList = this->getDirect3DDrivers();
180
181                optDevice.name = "Rendering Device";
182                optDevice.currentValue.clear();
183                optDevice.possibleValues.clear();
184                optDevice.immutable = false;
185
186                optVideoMode.name = "Video Mode";
187                optVideoMode.currentValue = "800 x 600 @ 32-bit colour";
188                optVideoMode.immutable = false;
189
190                optFullScreen.name = "Full Screen";
191                optFullScreen.possibleValues.push_back( "Yes" );
192                optFullScreen.possibleValues.push_back( "No" );
193                optFullScreen.currentValue = "Yes";
194                optFullScreen.immutable = false;
195
196                for( unsigned j=0; j < driverList->count(); j++ )
197                {
198                        driver = driverList->item(j);
199                        optDevice.possibleValues.push_back( driver->DriverDescription() );
200                        // Make first one default
201                        if( j==0 )
202                                optDevice.currentValue = driver->DriverDescription();
203                }
204
205                optVSync.name = "VSync";
206                optVSync.immutable = false;
207                optVSync.possibleValues.push_back( "Yes" );
208                optVSync.possibleValues.push_back( "No" );
209                optVSync.currentValue = "No";
210
211                optAA.name = "Anti aliasing";
212                optAA.immutable = false;
213                optAA.possibleValues.push_back( "None" );
214                optAA.currentValue = "None";
215
216                optFPUMode.name = "Floating-point mode";
217#if OGRE_DOUBLE_PRECISION
218                optFPUMode.currentValue = "Consistent";
219#else
220                optFPUMode.currentValue = "Fastest";
221#endif
222                optFPUMode.possibleValues.clear();
223                optFPUMode.possibleValues.push_back("Fastest");
224                optFPUMode.possibleValues.push_back("Consistent");
225                optFPUMode.immutable = false;
226
227                optNVPerfHUD.currentValue = "No";
228                optNVPerfHUD.immutable = false;
229                optNVPerfHUD.name = "Allow NVPerfHUD";
230                optNVPerfHUD.possibleValues.push_back( "Yes" );
231                optNVPerfHUD.possibleValues.push_back( "No" );
232
233                mOptions[optDevice.name] = optDevice;
234                mOptions[optVideoMode.name] = optVideoMode;
235                mOptions[optFullScreen.name] = optFullScreen;
236                mOptions[optVSync.name] = optVSync;
237                mOptions[optAA.name] = optAA;
238                mOptions[optFPUMode.name] = optFPUMode;
239                mOptions[optNVPerfHUD.name] = optNVPerfHUD;
240
241                refreshD3DSettings();
242
243        }
244        //---------------------------------------------------------------------
245        void D3D9RenderSystem::refreshD3DSettings()
246        {
247                ConfigOption* optVideoMode;
248                D3D9Driver* driver = 0;
249                D3D9VideoMode* videoMode;
250
251                ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
252                if( opt != mOptions.end() )
253                {
254                        for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
255                        {
256                                driver = getDirect3DDrivers()->item(j);
257                                if( driver->DriverDescription() == opt->second.currentValue )
258                                        break;
259                        }
260
261                        if (driver)
262                        {
263                                opt = mOptions.find( "Video Mode" );
264                                optVideoMode = &opt->second;
265                                optVideoMode->possibleValues.clear();
266                                // get vide modes for this device
267                                for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ )
268                                {
269                                        videoMode = driver->getVideoModeList()->item( k );
270                                        optVideoMode->possibleValues.push_back( videoMode->getDescription() );
271                                }
272
273                // Reset video mode to default if previous doesn't avail in new possible values
274                StringVector::const_iterator itValue =
275                    std::find(optVideoMode->possibleValues.begin(),
276                              optVideoMode->possibleValues.end(),
277                              optVideoMode->currentValue);
278                if (itValue == optVideoMode->possibleValues.end())
279                {
280                    optVideoMode->currentValue = "800 x 600 @ 32-bit colour";
281                }
282
283                // Also refresh FSAA options
284                refreshFSAAOptions();
285                        }
286                }
287
288        }
289        //---------------------------------------------------------------------
290        void D3D9RenderSystem::setConfigOption( const String &name, const String &value )
291        {
292
293        StringUtil::StrStreamType str;
294        str << "D3D9 : RenderSystem Option: " << name << " = " << value;
295                LogManager::getSingleton().logMessage(str.str());
296
297        bool viewModeChanged = false;
298
299                // Find option
300                ConfigOptionMap::iterator it = mOptions.find( name );
301
302                // Update
303                if( it != mOptions.end() )
304                        it->second.currentValue = value;
305                else
306                {
307            str.str(StringUtil::BLANK);
308            str << "Option named '" << name << "' does not exist.";
309                        OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, str.str(), "D3D9RenderSystem::setConfigOption" );
310                }
311
312                // Refresh other options if D3DDriver changed
313                if( name == "Rendering Device" )
314                        refreshD3DSettings();
315
316                if( name == "Full Screen" )
317                {
318                        // Video mode is applicable
319                        it = mOptions.find( "Video Mode" );
320                        if (it->second.currentValue.empty())
321            {
322                                it->second.currentValue = "800 x 600 @ 32-bit colour";
323                viewModeChanged = true;
324            }
325                }
326
327                if( name == "Anti aliasing" )
328                {
329                        if (value == "None")
330                                _setFSAA(D3DMULTISAMPLE_NONE, 0);
331                        else 
332                        {
333                                D3DMULTISAMPLE_TYPE fsaa = D3DMULTISAMPLE_NONE;
334                                DWORD level = 0;
335
336                                if (StringUtil::startsWith(value, "NonMaskable", false))
337                                {
338                                        fsaa = D3DMULTISAMPLE_NONMASKABLE;
339                                        size_t pos = value.find_last_of(" ");
340                                        String sNum = value.substr(pos + 1);
341                                        level = StringConverter::parseInt(sNum);
342                                        level -= 1;
343                                }
344                                else if (StringUtil::startsWith(value, "Level", false))
345                                {
346                                        size_t pos = value.find_last_of(" ");
347                                        String sNum = value.substr(pos + 1);
348                                        fsaa = (D3DMULTISAMPLE_TYPE)StringConverter::parseInt(sNum);
349                                }
350
351                                _setFSAA(fsaa, level);
352                        }
353                }
354
355                if( name == "VSync" )
356                {
357                        if (value == "Yes")
358                                mVSync = true;
359                        else
360                                mVSync = false;
361                }
362
363                if( name == "Allow NVPerfHUD" )
364                {
365                        if (value == "Yes")
366                                mUseNVPerfHUD = true;
367                        else
368                                mUseNVPerfHUD = false;
369                }
370
371                if (viewModeChanged || name == "Video Mode")
372                {
373            refreshFSAAOptions();
374                }
375
376        }
377        //---------------------------------------------------------------------
378    void D3D9RenderSystem::refreshFSAAOptions(void)
379    {
380
381        ConfigOptionMap::iterator it = mOptions.find( "Anti aliasing" );
382        ConfigOption* optFSAA = &it->second;
383        optFSAA->possibleValues.clear();
384        optFSAA->possibleValues.push_back("None");
385
386        it = mOptions.find("Rendering Device");
387        D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue);
388        if (driver)
389        {
390            it = mOptions.find("Video Mode");
391            D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue);
392            if (videoMode)
393            {
394                // get non maskable FSAA for this VMODE
395                DWORD numLevels = 0;
396                bool bOK = this->_checkMultiSampleQuality(
397                    D3DMULTISAMPLE_NONMASKABLE, 
398                    &numLevels, 
399                    videoMode->getFormat(), 
400                    driver->getAdapterNumber(),
401                    D3DDEVTYPE_HAL,
402                    TRUE);
403                if (bOK && numLevels > 0)
404                {
405                    for (DWORD n = 0; n < numLevels; n++)
406                        optFSAA->possibleValues.push_back("NonMaskable " + StringConverter::toString(n + 1));
407                }
408
409                // set maskable levels supported
410                for (unsigned int n = 2; n < 17; n++)
411                {
412                    bOK = this->_checkMultiSampleQuality(
413                        (D3DMULTISAMPLE_TYPE)n, 
414                        &numLevels, 
415                        videoMode->getFormat(), 
416                        driver->getAdapterNumber(),
417                        D3DDEVTYPE_HAL,
418                        TRUE);
419                    if (bOK)
420                        optFSAA->possibleValues.push_back("Level " + StringConverter::toString(n));
421                }
422            }
423        }
424
425        // Reset FSAA to none if previous doesn't avail in new possible values
426        StringVector::const_iterator itValue =
427            std::find(optFSAA->possibleValues.begin(),
428                      optFSAA->possibleValues.end(),
429                      optFSAA->currentValue);
430        if (itValue == optFSAA->possibleValues.end())
431        {
432            optFSAA->currentValue = "None";
433        }
434
435    }
436        //---------------------------------------------------------------------
437        String D3D9RenderSystem::validateConfigOptions()
438        {
439                ConfigOptionMap::iterator it;
440               
441                // check if video mode is selected
442                it = mOptions.find( "Video Mode" );
443                if (it->second.currentValue.empty())
444                        return "A video mode must be selected.";
445
446                it = mOptions.find( "Rendering Device" );
447                bool foundDriver = false;
448                D3D9DriverList* driverList = getDirect3DDrivers();
449                for( ushort j=0; j < driverList->count(); j++ )
450                {
451                        if( driverList->item(j)->DriverDescription() == it->second.currentValue )
452                        {
453                                foundDriver = true;
454                                break;
455                        }
456                }
457
458                if (!foundDriver)
459                {
460                        // Just pick the first driver
461                        setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
462                        return "Your DirectX driver name has changed since the last time you ran OGRE; "
463                                "the 'Rendering Device' has been changed.";
464                }
465
466        it = mOptions.find( "VSync" );
467                if( it->second.currentValue == "Yes" )
468                        mVSync = true;
469                else
470                        mVSync = false;
471
472        return StringUtil::BLANK;
473        }
474        //---------------------------------------------------------------------
475        ConfigOptionMap& D3D9RenderSystem::getConfigOptions()
476        {
477                // return a COPY of the current config options
478                return mOptions;
479        }
480        //---------------------------------------------------------------------
481        RenderWindow* D3D9RenderSystem::initialise( bool autoCreateWindow, const String& windowTitle )
482        {
483                RenderWindow* autoWindow = NULL;
484                LogManager::getSingleton().logMessage( "D3D9 : Subsystem Initialising" );
485
486                // Init using current settings
487                mActiveD3DDriver = NULL;
488                ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
489                for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
490                {
491                        if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
492                        {
493                                mActiveD3DDriver = getDirect3DDrivers()->item(j);
494                                break;
495                        }
496                }
497
498                if( !mActiveD3DDriver )
499                        OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Problems finding requested Direct3D driver!", "D3D9RenderSystem::initialise" );
500
501                if( autoCreateWindow )
502                {
503                        bool fullScreen;
504                        opt = mOptions.find( "Full Screen" );
505                        if( opt == mOptions.end() )
506                                OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find full screen option!", "D3D9RenderSystem::initialise" );
507                        fullScreen = opt->second.currentValue == "Yes";
508
509                        D3D9VideoMode* videoMode = NULL;
510                        unsigned int width, height;
511                        String temp;
512
513                        opt = mOptions.find( "Video Mode" );
514                        if( opt == mOptions.end() )
515                                OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find Video Mode option!", "D3D9RenderSystem::initialise" );
516
517                        // The string we are manipulating looks like this :width x height @ colourDepth
518                        // Pull out the colour depth by getting what comes after the @ and a space
519                        String colourDepth = opt->second.currentValue.substr(opt->second.currentValue.rfind('@')+1);
520                        // Now we know that the width starts a 0, so if we can find the end we can parse that out
521                        String::size_type widthEnd = opt->second.currentValue.find(' ');
522                        // we know that the height starts 3 characters after the width and goes until the next space
523                        String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd+3);
524                        // Now we can parse out the values
525                        width = StringConverter::parseInt(opt->second.currentValue.substr(0, widthEnd));
526                        height = StringConverter::parseInt(opt->second.currentValue.substr(widthEnd+3, heightEnd));
527
528                        for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ )
529                        {
530                                temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription();
531
532                                // In full screen we only want to allow supported resolutions, so temp and opt->second.currentValue need to
533                                // match exacly, but in windowed mode we can allow for arbitrary window sized, so we only need
534                                // to match the colour values
535                                if(fullScreen && (temp == opt->second.currentValue) ||
536                                  !fullScreen && (temp.substr(temp.rfind('@')+1) == colourDepth))
537                                {
538                                        videoMode = mActiveD3DDriver->getVideoModeList()->item(j);
539                                        break;
540                                }
541                        }
542
543                        if( !videoMode )
544                                OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find requested video mode.", "D3D9RenderSystem::initialise" );
545                       
546                        NameValuePairList miscParams;
547                        miscParams["colourDepth"] = StringConverter::toString(videoMode->getColourDepth());
548                        miscParams["FSAA"] = StringConverter::toString(mFSAAType);
549                        miscParams["FSAAQuality"] = StringConverter::toString(mFSAAQuality);
550                        miscParams["vsync"] = StringConverter::toString(mVSync);
551                        miscParams["useNVPerfHUD"] = StringConverter::toString(mUseNVPerfHUD);
552
553                        autoWindow = this->createRenderWindow( windowTitle, width, height, 
554                                fullScreen, &miscParams );
555
556            // If we have 16bit depth buffer enable w-buffering.
557            assert( autoWindow );
558            if ( autoWindow->getColourDepth() == 16 ) 
559            { 
560                mWBuffer = true;
561            } 
562            else 
563            {
564                mWBuffer = false;
565            }
566                }
567
568                LogManager::getSingleton().logMessage("***************************************");
569                LogManager::getSingleton().logMessage("*** D3D9 : Subsystem Initialised OK ***");
570                LogManager::getSingleton().logMessage("***************************************");
571
572                // call superclass method
573                RenderSystem::initialise( autoCreateWindow );
574
575
576                return autoWindow;
577        }
578        //---------------------------------------------------------------------
579        void D3D9RenderSystem::_setFSAA(D3DMULTISAMPLE_TYPE type, DWORD qualityLevel)
580        {
581                if (!mpD3DDevice)
582                {
583                        mFSAAType = type;
584                        mFSAAQuality = qualityLevel;
585                }
586        }
587        //---------------------------------------------------------------------
588        void D3D9RenderSystem::reinitialise()
589        {
590                LogManager::getSingleton().logMessage( "D3D9 : Reinitialising" );
591                this->shutdown();
592                this->initialise( true );
593        }
594        //---------------------------------------------------------------------
595        void D3D9RenderSystem::shutdown()
596        {
597                RenderSystem::shutdown();
598                mPrimaryWindow = NULL; // primary window deleted by base class.
599                freeDevice();
600                SAFE_DELETE( mDriverList );
601                mActiveD3DDriver = NULL;
602                mpD3DDevice = NULL;
603                mBasicStatesInitialised = false;
604                LogManager::getSingleton().logMessage("D3D9 : Shutting down cleanly.");
605                SAFE_DELETE( mTextureManager );
606                SAFE_DELETE( mHardwareBufferManager );
607                SAFE_DELETE( mGpuProgramManager );
608        }
609        //---------------------------------------------------------------------
610        RenderWindow* D3D9RenderSystem::createRenderWindow(const String &name, 
611                unsigned int width, unsigned int height, bool fullScreen,
612                const NameValuePairList *miscParams)
613        {
614
615                // Check we're not creating a secondary window when the primary
616                // was fullscreen
617                if (mPrimaryWindow && mPrimaryWindow->isFullScreen())
618                {
619                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
620                                "Cannot create secondary windows when the primary is full screen",
621                                "D3D9RenderSystem::createRenderWindow");
622                }
623                if (mPrimaryWindow && fullScreen)
624                {
625                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
626                                "Cannot create full screen secondary windows",
627                                "D3D9RenderSystem::createRenderWindow");
628                }
629               
630                // Log a message
631                std::stringstream ss;
632                ss << "D3D9RenderSystem::createRenderWindow \"" << name << "\", " <<
633                        width << "x" << height << " ";
634                if(fullScreen)
635                        ss << "fullscreen ";
636                else
637                        ss << "windowed ";
638                if(miscParams)
639                {
640                        ss << " miscParams: ";
641                        NameValuePairList::const_iterator it;
642                        for(it=miscParams->begin(); it!=miscParams->end(); ++it)
643                        {
644                                ss << it->first << "=" << it->second << " ";
645                        }
646                        LogManager::getSingleton().logMessage(ss.str());
647                }
648               
649                String msg;
650
651                // Make sure we don't already have a render target of the
652                // sam name as the one supplied
653                if( mRenderTargets.find( name ) != mRenderTargets.end() )
654                {
655                        msg = "A render target of the same name '" + name + "' already "
656                                "exists.  You cannot create a new window with this name.";
657                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, msg, "D3D9RenderSystem::createRenderWindow" );
658                }
659
660                RenderWindow* win = new D3D9RenderWindow(mhInstance, mActiveD3DDriver, 
661                        mPrimaryWindow ? mpD3DDevice : 0);
662
663                win->create( name, width, height, fullScreen, miscParams);
664
665                attachRenderTarget( *win );
666
667                // If this is the first window, get the D3D device and create the texture manager
668                if( !mPrimaryWindow )
669                {
670                        mPrimaryWindow = (D3D9RenderWindow *)win;
671                        win->getCustomAttribute( "D3DDEVICE", &mpD3DDevice );
672
673                        // Create the texture manager for use by others
674                        mTextureManager = new D3D9TextureManager( mpD3DDevice );
675            // Also create hardware buffer manager
676            mHardwareBufferManager = new D3D9HardwareBufferManager(mpD3DDevice);
677
678                        // Create the GPU program manager
679                        mGpuProgramManager = new D3D9GpuProgramManager(mpD3DDevice);
680            // create & register HLSL factory
681                        if (mHLSLProgramFactory == NULL)
682                                mHLSLProgramFactory = new D3D9HLSLProgramFactory();
683            HighLevelGpuProgramManager::getSingleton().addFactory(mHLSLProgramFactory);
684            mGpuProgramManager->_pushSyntaxCode("hlsl");
685
686
687            // Initialise the capabilities structures
688            initCapabilities();
689
690                }
691                else
692                {
693                        mSecondaryWindows.push_back(static_cast<D3D9RenderWindow *>(win));
694                }
695
696                return win;
697
698        }
699    //---------------------------------------------------------------------
700    void D3D9RenderSystem::initCapabilities(void)
701    {
702                // get caps
703                mpD3DDevice->GetDeviceCaps( &mCaps );
704
705        // Check for hardware stencil support
706                LPDIRECT3DSURFACE9 pSurf;
707                D3DSURFACE_DESC surfDesc;
708                mpD3DDevice->GetDepthStencilSurface(&pSurf);
709                pSurf->GetDesc(&surfDesc);
710                pSurf->Release();
711
712                if (surfDesc.Format == D3DFMT_D24S8 || surfDesc.Format == D3DFMT_D24X8)
713                {
714                        mCapabilities->setCapability(RSC_HWSTENCIL);
715                        // Actually, it's always 8-bit
716                        mCapabilities->setStencilBufferBitDepth(8);
717
718                }
719
720                // Set number of texture units
721                mCapabilities->setNumTextureUnits(mCaps.MaxSimultaneousTextures);
722        // Anisotropy?
723        if (mCaps.MaxAnisotropy > 1)
724            mCapabilities->setCapability(RSC_ANISOTROPY);
725        // Automatic mipmap generation?
726        if (mCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
727            mCapabilities->setCapability(RSC_AUTOMIPMAP);
728        // Blending between stages supported
729        mCapabilities->setCapability(RSC_BLENDING);
730        // Dot 3
731        if (mCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3)
732            mCapabilities->setCapability(RSC_DOT3);
733        // Cube map
734        if (mCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP)
735            mCapabilities->setCapability(RSC_CUBEMAPPING);
736
737        // We always support compression, D3DX will decompress if device does not support
738        mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION);
739        mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION_DXT);
740
741        // We always support VBOs
742        mCapabilities->setCapability(RSC_VBO);
743
744        // Scissor test
745        if (mCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST)
746            mCapabilities->setCapability(RSC_SCISSOR_TEST);
747
748        // Two-sided stencil
749        if (mCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED)
750            mCapabilities->setCapability(RSC_TWO_SIDED_STENCIL);
751
752        // stencil wrap
753        if ((mCaps.StencilCaps & D3DSTENCILCAPS_INCR) && 
754            (mCaps.StencilCaps & D3DSTENCILCAPS_DECR))
755            mCapabilities->setCapability(RSC_STENCIL_WRAP);
756
757        // Check for hardware occlusion support
758        if ( ( mpD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION,  NULL ) ) == D3D_OK )   
759        {
760            mCapabilities->setCapability(RSC_HWOCCLUSION);
761        }
762        convertVertexShaderCaps();
763        convertPixelShaderCaps();
764
765                // User clip planes
766        if (mCaps.MaxUserClipPlanes > 0)
767                {
768                        mCapabilities->setCapability(RSC_USER_CLIP_PLANES);
769                }
770
771                // UBYTE4 type?
772                if (mCaps.DeclTypes & D3DDTCAPS_UBYTE4)
773                {
774                        mCapabilities->setCapability(RSC_VERTEX_FORMAT_UBYTE4);
775                }
776
777                // Adapter details
778                const D3DADAPTER_IDENTIFIER9& adapterID = mActiveD3DDriver->getAdapterIdentifier();
779
780                // Infinite projection?
781                // We have no capability for this, so we have to base this on our
782                // experience and reports from users
783                // Non-vertex program capable hardware does not appear to support it
784                if (mCapabilities->hasCapability(RSC_VERTEX_PROGRAM))
785                {
786                        // GeForce4 Ti (and presumably GeForce3) does not
787                        // render infinite projection properly, even though it does in GL
788            // So exclude all cards prior to the FX range from doing infinite
789                        if (adapterID.VendorId != 0x10DE || // not nVidia
790                                !((adapterID.DeviceId >= 0x200 && adapterID.DeviceId <= 0x20F) || //gf3
791                                  (adapterID.DeviceId >= 0x250 && adapterID.DeviceId <= 0x25F) || //gf4ti
792                                  (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F) || //gf4ti
793                                  (adapterID.DeviceId >= 0x170 && adapterID.DeviceId <= 0x18F) || //gf4 go
794                                  (adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F)))  //gf4ti go
795                        {
796                                mCapabilities->setCapability(RSC_INFINITE_FAR_PLANE);
797                        }
798                       
799                }
800               
801                // 3D textures?
802                if (mCaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP)
803                {
804                        mCapabilities->setCapability(RSC_TEXTURE_3D);
805                }
806               
807        if ((mCaps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0)
808                {
809                        // unrestricted non POW2
810                        mCapabilities->setCapability(RSC_NON_POWER_OF_2_TEXTURES);
811                }
812                else if (mCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
813                {
814                        // Conditional support for non POW2
815                        mCapabilities->setCapability(RSC_NON_POWER_OF_2_TEXTURES);
816                        mCapabilities->setNonPOW2TexturesLimited(true);
817
818                }
819
820                // We always support rendertextures bigger than the frame buffer
821        mCapabilities->setCapability(RSC_HWRENDER_TO_TEXTURE);
822
823                // Determine if any floating point texture format is supported
824                D3DFORMAT floatFormats[6] = {D3DFMT_R16F, D3DFMT_G16R16F, 
825                        D3DFMT_A16B16G16R16F, D3DFMT_R32F, D3DFMT_G32R32F, 
826                        D3DFMT_A32B32G32R32F};
827                LPDIRECT3DSURFACE9 bbSurf;
828                mPrimaryWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf);
829                D3DSURFACE_DESC bbSurfDesc;
830                bbSurf->GetDesc(&bbSurfDesc);
831               
832                for (int i = 0; i < 6; ++i)
833                {
834                        if (SUCCEEDED(mpD3D->CheckDeviceFormat(mActiveD3DDriver->getAdapterNumber(), 
835                                D3DDEVTYPE_HAL, bbSurfDesc.Format, 
836                                0, D3DRTYPE_TEXTURE, floatFormats[i])))
837                        {
838                                mCapabilities->setCapability(RSC_TEXTURE_FLOAT);
839                                break;
840                        }
841                       
842                }
843               
844                // Number of render targets
845                mCapabilities->setNumMultiRenderTargets(std::min((ushort)mCaps.NumSimultaneousRTs, (ushort)OGRE_MAX_MULTIPLE_RENDER_TARGETS));
846
847                //
848                if(mCaps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS)
849                {
850                        LogManager::getSingleton().logMessage("Multiple render targets with independent bit depths supported");
851                }
852
853                // Point sprites
854                if (mCaps.MaxPointSize > 1.0f)
855                {
856                        mCapabilities->setCapability(RSC_POINT_SPRITES);
857                        // sprites and extended parameters go together in D3D
858                        mCapabilities->setCapability(RSC_POINT_EXTENDED_PARAMETERS);
859                        mCapabilities->setMaxPointSize(mCaps.MaxPointSize);
860                }
861
862                // Vertex textures
863                if (mGpuProgramManager->isSyntaxSupported("vs_3_0"))
864                {
865                        // Run through all the texture formats looking for any which support
866                        // vertex texture fetching. Must have at least one!
867                        // All ATI Radeon up to X1n00 say they support vs_3_0,
868                        // but they support no texture formats for vertex texture fetch (cheaters!)
869                        if (checkVertexTextureFormats())
870                        {
871                                mCapabilities->setCapability(RSC_VERTEX_TEXTURE_FETCH);
872                                // always 4 vertex texture units in vs_3_0, and never shared
873                                mCapabilities->setNumVertexTextureUnits(4);
874                                mCapabilities->setVertexTextureUnitsShared(false);
875
876                        }
877                }
878
879                // Mipmap LOD biasing?
880                if (mCaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS)
881                {
882                        mCapabilities->setCapability(RSC_MIPMAP_LOD_BIAS);
883                }
884               
885
886                Log* defaultLog = LogManager::getSingleton().getDefaultLog();
887                if (defaultLog)
888                {
889                        mCapabilities->log(defaultLog);
890                }
891
892                // Do we support per-stage src_manual constants?
893                // HACK - ATI drivers seem to be buggy and don't support per-stage constants properly?
894                mPerStageConstantSupport = (mCaps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) != 0;
895
896    }
897    //---------------------------------------------------------------------
898    void D3D9RenderSystem::convertVertexShaderCaps(void)
899    {
900        ushort major, minor;
901        major = static_cast<ushort>((mCaps.VertexShaderVersion & 0x0000FF00) >> 8);
902        minor = static_cast<ushort>(mCaps.VertexShaderVersion & 0x000000FF);
903
904        bool vs2x = false;
905        bool vs2a = false;
906
907        // Special case detection for vs_2_x/a support
908        if (major >= 2)
909        {
910            if ((mCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
911                (mCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
912                (mCaps.VS20Caps.NumTemps >= 12))
913            {
914                vs2x = true;
915            }
916
917            if ((mCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
918                (mCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
919                (mCaps.VS20Caps.NumTemps >= 13))
920            {
921                vs2a = true;
922            }
923        }
924
925        // Populate max version & params
926        switch (major)
927        {
928        case 1:
929            mCapabilities->setMaxVertexProgramVersion("vs_1_1");
930            // No boolean params allowed
931            mCapabilities->setVertexProgramConstantBoolCount(0);
932            // No integer params allowed
933            mCapabilities->setVertexProgramConstantIntCount(0);
934            // float params, always 4D
935            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
936           
937            break;
938        case 2:
939            if (vs2a)
940            {
941                mCapabilities->setMaxVertexProgramVersion("vs_2_a");
942            }
943            else if (vs2x)
944            {
945                mCapabilities->setMaxVertexProgramVersion("vs_2_x");
946            }
947            else
948            {
949                mCapabilities->setMaxVertexProgramVersion("vs_2_0");
950            }
951            // 16 boolean params allowed
952            mCapabilities->setVertexProgramConstantBoolCount(16);
953            // 16 integer params allowed, 4D
954            mCapabilities->setVertexProgramConstantIntCount(16);
955            // float params, always 4D
956            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
957            break;
958        case 3:
959            mCapabilities->setMaxVertexProgramVersion("vs_3_0");
960            // 16 boolean params allowed
961            mCapabilities->setVertexProgramConstantBoolCount(16);
962            // 16 integer params allowed, 4D
963            mCapabilities->setVertexProgramConstantIntCount(16);
964            // float params, always 4D
965            mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
966            break;
967        default:
968            mCapabilities->setMaxVertexProgramVersion(StringUtil::BLANK);
969            break;
970        }
971
972        // populate syntax codes in program manager (no breaks in this one so it falls through)
973        switch(major)
974        {
975        case 3:
976            mGpuProgramManager->_pushSyntaxCode("vs_3_0");
977        case 2:
978            if (vs2x)
979                mGpuProgramManager->_pushSyntaxCode("vs_2_x");
980            if (vs2a)
981                mGpuProgramManager->_pushSyntaxCode("vs_2_a");
982
983            mGpuProgramManager->_pushSyntaxCode("vs_2_0");
984        case 1:
985            mGpuProgramManager->_pushSyntaxCode("vs_1_1");
986            mCapabilities->setCapability(RSC_VERTEX_PROGRAM);
987        }
988    }
989    //---------------------------------------------------------------------
990    void D3D9RenderSystem::convertPixelShaderCaps(void)
991    {
992        ushort major, minor;
993        major = static_cast<ushort>((mCaps.PixelShaderVersion & 0x0000FF00) >> 8);
994        minor = static_cast<ushort>(mCaps.PixelShaderVersion & 0x000000FF);
995
996                bool ps2a = false;
997        bool ps2b = false;
998        bool ps2x = false;
999
1000        // Special case detection for ps_2_x/a/b support
1001        if (major >= 2)
1002        {
1003                        if ((mCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
1004                (mCaps.PS20Caps.NumTemps >= 32))
1005            {
1006                ps2b = true;
1007            }
1008
1009                if ((mCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
1010                (mCaps.PS20Caps.Caps & D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
1011                (mCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE) &&
1012                                (mCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
1013                                (mCaps.PS20Caps.Caps & D3DPS20CAPS_PREDICATION) &&
1014                (mCaps.PS20Caps.NumTemps >= 22))
1015                {
1016                ps2a = true;
1017                        }
1018
1019            // Does this enough?
1020            if (ps2a || ps2b)
1021            {
1022                ps2x = true;
1023            }
1024        }
1025
1026        switch (major)
1027        {
1028        case 1:
1029            switch(minor)
1030            {
1031            case 1:
1032                mCapabilities->setMaxFragmentProgramVersion("ps_1_1");
1033                break;
1034            case 2:
1035                mCapabilities->setMaxFragmentProgramVersion("ps_1_2");
1036                break;
1037            case 3:
1038                mCapabilities->setMaxFragmentProgramVersion("ps_1_3");
1039                break;
1040            case 4:
1041                mCapabilities->setMaxFragmentProgramVersion("ps_1_4");
1042                break;
1043            }
1044            // no boolean params allowed
1045            mCapabilities->setFragmentProgramConstantBoolCount(0);
1046            // no integer params allowed
1047            mCapabilities->setFragmentProgramConstantIntCount(0);
1048            // float params, always 4D
1049            // NB in ps_1_x these are actually stored as fixed point values,
1050            // but they are entered as floats
1051            mCapabilities->setFragmentProgramConstantFloatCount(8);
1052            break;
1053        case 2:
1054                        if (ps2a)
1055            {
1056                mCapabilities->setMaxFragmentProgramVersion("ps_2_a");
1057            }
1058                        else if (ps2b)
1059            {
1060                mCapabilities->setMaxFragmentProgramVersion("ps_2_b");
1061            }
1062                        else if (ps2x)
1063            {
1064                mCapabilities->setMaxFragmentProgramVersion("ps_2_x");
1065            }
1066            else
1067            {
1068                mCapabilities->setMaxFragmentProgramVersion("ps_2_0");
1069            }
1070            // 16 boolean params allowed
1071            mCapabilities->setFragmentProgramConstantBoolCount(16);
1072            // 16 integer params allowed, 4D
1073            mCapabilities->setFragmentProgramConstantIntCount(16);
1074            // float params, always 4D
1075            mCapabilities->setFragmentProgramConstantFloatCount(32);
1076            break;
1077        case 3:
1078            if (minor > 0)
1079            {
1080                mCapabilities->setMaxFragmentProgramVersion("ps_3_x");
1081            }
1082            else
1083            {
1084                mCapabilities->setMaxFragmentProgramVersion("ps_3_0");
1085            }
1086            // 16 boolean params allowed
1087            mCapabilities->setFragmentProgramConstantBoolCount(16);
1088            // 16 integer params allowed, 4D
1089            mCapabilities->setFragmentProgramConstantIntCount(16);
1090            // float params, always 4D
1091            mCapabilities->setFragmentProgramConstantFloatCount(224);
1092            break;
1093        default:
1094            mCapabilities->setMaxFragmentProgramVersion(StringUtil::BLANK);
1095            break;
1096        }
1097
1098        // populate syntax codes in program manager (no breaks in this one so it falls through)
1099        switch(major)
1100        {
1101        case 3:
1102            if (minor > 0)
1103                mGpuProgramManager->_pushSyntaxCode("ps_3_x");
1104
1105            mGpuProgramManager->_pushSyntaxCode("ps_3_0");
1106        case 2:
1107            if (ps2x)
1108                mGpuProgramManager->_pushSyntaxCode("ps_2_x");
1109            if (ps2a)
1110                mGpuProgramManager->_pushSyntaxCode("ps_2_a");
1111            if (ps2b)
1112                mGpuProgramManager->_pushSyntaxCode("ps_2_b");
1113
1114            mGpuProgramManager->_pushSyntaxCode("ps_2_0");
1115        case 1:
1116            if (major > 1 || minor >= 4)
1117                mGpuProgramManager->_pushSyntaxCode("ps_1_4");
1118            if (major > 1 || minor >= 3)
1119                mGpuProgramManager->_pushSyntaxCode("ps_1_3");
1120            if (major > 1 || minor >= 2)
1121                mGpuProgramManager->_pushSyntaxCode("ps_1_2");
1122           
1123            mGpuProgramManager->_pushSyntaxCode("ps_1_1");
1124            mCapabilities->setCapability(RSC_FRAGMENT_PROGRAM);
1125        }
1126    }
1127        //-----------------------------------------------------------------------
1128        bool D3D9RenderSystem::checkVertexTextureFormats(void)
1129        {
1130                bool anySupported = false;
1131
1132                LPDIRECT3DSURFACE9 bbSurf;
1133                mPrimaryWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf);
1134                D3DSURFACE_DESC bbSurfDesc;
1135                bbSurf->GetDesc(&bbSurfDesc);
1136
1137                for (uint ipf = (uint)PF_L8; ipf < (uint)PF_COUNT; ++ipf)
1138                {
1139                        PixelFormat pf = (PixelFormat)ipf;
1140
1141                        D3DFORMAT fmt = 
1142                                D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(pf));
1143
1144                        if (SUCCEEDED(mpD3D->CheckDeviceFormat(
1145                                mActiveD3DDriver->getAdapterNumber(), D3DDEVTYPE_HAL, bbSurfDesc.Format, 
1146                                D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, fmt)))
1147                        {
1148                                // cool, at least one supported
1149                                anySupported = true;
1150                                StringUtil::StrStreamType str;
1151                                str << "D3D9: Vertex texture format supported - "
1152                                        << PixelUtil::getFormatName(pf);
1153                                LogManager::getSingleton().logMessage(str.str());
1154                        }
1155                }
1156
1157                return anySupported;
1158
1159
1160        }
1161        //-----------------------------------------------------------------------
1162    bool D3D9RenderSystem::_checkTextureFilteringSupported(TextureType ttype, PixelFormat format, int usage)
1163    {
1164                // Gets D3D format
1165                D3DFORMAT d3dPF = D3D9Mappings::_getPF(format);
1166        if (d3dPF == D3DFMT_UNKNOWN)
1167            return false;
1168
1169                LPDIRECT3DSURFACE9 pSurface = mPrimaryWindow->getRenderSurface();
1170                D3DSURFACE_DESC srfDesc;
1171                if (FAILED(pSurface->GetDesc(&srfDesc)))
1172            return false;
1173
1174                // Calculate usage
1175                DWORD d3dusage = D3DUSAGE_QUERY_FILTER;
1176                if (usage & TU_RENDERTARGET) 
1177                        d3dusage |= D3DUSAGE_RENDERTARGET;
1178                if (usage & TU_DYNAMIC)
1179                        d3dusage |= D3DUSAGE_DYNAMIC;
1180
1181        // Detect resource type
1182        D3DRESOURCETYPE rtype;
1183                switch(ttype)
1184                {
1185                case TEX_TYPE_1D:
1186                case TEX_TYPE_2D:
1187            rtype = D3DRTYPE_TEXTURE;
1188            break;
1189        case TEX_TYPE_3D:
1190            rtype = D3DRTYPE_VOLUMETEXTURE;
1191            break;
1192        case TEX_TYPE_CUBE_MAP:
1193            rtype = D3DRTYPE_CUBETEXTURE;
1194            break;
1195        default:
1196            return false;
1197        }
1198
1199        HRESULT hr = mpD3D->CheckDeviceFormat(
1200            mActiveD3DDriver->getAdapterNumber(),
1201            D3DDEVTYPE_HAL,
1202            srfDesc.Format,
1203            d3dusage,
1204            rtype,
1205            d3dPF);
1206
1207        return SUCCEEDED(hr);
1208    }
1209        //-----------------------------------------------------------------------
1210        MultiRenderTarget * D3D9RenderSystem::createMultiRenderTarget(const String & name)
1211        {
1212                MultiRenderTarget *retval;
1213                retval = new D3D9MultiRenderTarget(name);
1214                attachRenderTarget(*retval);
1215
1216                return retval;
1217        }
1218        //---------------------------------------------------------------------
1219        void D3D9RenderSystem::destroyRenderTarget(const String& name)
1220        {
1221                // Check in specialised lists
1222                if (mPrimaryWindow->getName() == name)
1223                {
1224                        // We're destroying the primary window, so reset device and window
1225                        mPrimaryWindow = 0;
1226                }
1227                else
1228                {
1229                        // Check secondary windows
1230                        SecondaryWindowList::iterator sw;
1231                        for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
1232                        {
1233                                if ((*sw)->getName() == name)
1234                                {
1235                                        mSecondaryWindows.erase(sw);
1236                                        break;
1237                                }
1238                        }
1239                }
1240                // Do the real removal
1241                RenderSystem::destroyRenderTarget(name);
1242
1243                // Did we destroy the primary?
1244                if (!mPrimaryWindow)
1245                {
1246                        // device is no longer valid, so free it all up
1247                        freeDevice();
1248                }
1249
1250        }
1251        //-----------------------------------------------------------------------
1252        void D3D9RenderSystem::freeDevice(void)
1253        {
1254                if (mpD3DDevice)
1255                {
1256                        // Set all texture units to nothing to release texture surfaces
1257                        _disableTextureUnitsFrom(0);
1258                        // Unbind any vertex streams to avoid memory leaks
1259                        for (unsigned int i = 0; i < mLastVertexSourceCount; ++i)
1260                        {
1261                                HRESULT hr = mpD3DDevice->SetStreamSource(i, NULL, 0, 0);
1262                        }
1263                        // Clean up depth stencil surfaces
1264                        _cleanupDepthStencils();
1265                        SAFE_RELEASE(mpD3DDevice);
1266                        mActiveD3DDriver->setD3DDevice(NULL);
1267                        mpD3DDevice = 0;
1268
1269                }
1270
1271
1272        }
1273        //---------------------------------------------------------------------
1274        String D3D9RenderSystem::getErrorDescription( long errorNumber ) const
1275        {
1276                const String errMsg = DXGetErrorDescription9( errorNumber );
1277                return errMsg;
1278        }
1279    //---------------------------------------------------------------------
1280        VertexElementType D3D9RenderSystem::getColourVertexElementType(void) const
1281        {
1282                return VET_COLOUR_ARGB;
1283        }
1284        //---------------------------------------------------------------------
1285        void D3D9RenderSystem::_convertProjectionMatrix(const Matrix4& matrix,
1286        Matrix4& dest, bool forGpuProgram)
1287    {
1288        dest = matrix;
1289
1290        // Convert depth range from [-1,+1] to [0,1]
1291        dest[2][0] = (dest[2][0] + dest[3][0]) / 2;
1292        dest[2][1] = (dest[2][1] + dest[3][1]) / 2;
1293        dest[2][2] = (dest[2][2] + dest[3][2]) / 2;
1294        dest[2][3] = (dest[2][3] + dest[3][3]) / 2;
1295
1296        if (!forGpuProgram)
1297        {
1298            // Convert right-handed to left-handed
1299            dest[0][2] = -dest[0][2];
1300            dest[1][2] = -dest[1][2];
1301            dest[2][2] = -dest[2][2];
1302            dest[3][2] = -dest[3][2];
1303        }
1304    }
1305        //---------------------------------------------------------------------
1306        void D3D9RenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane, 
1307        Real farPlane, Matrix4& dest, bool forGpuProgram)
1308        {
1309        Radian theta ( fovy * 0.5 );
1310                Real h = 1 / Math::Tan(theta);
1311                Real w = h / aspect;
1312                Real q, qn;
1313        if (farPlane == 0)
1314        {
1315            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
1316            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
1317        }
1318        else
1319        {
1320            q = farPlane / ( farPlane - nearPlane );
1321            qn = -q * nearPlane;
1322        }
1323
1324                dest = Matrix4::ZERO;
1325                dest[0][0] = w;
1326                dest[1][1] = h;
1327
1328        if (forGpuProgram)
1329        {
1330            dest[2][2] = -q;
1331                    dest[3][2] = -1.0f;
1332        }
1333        else
1334        {
1335            dest[2][2] = q;
1336            dest[3][2] = 1.0f;
1337        }
1338
1339        dest[2][3] = qn;
1340        }
1341        //---------------------------------------------------------------------
1342        void D3D9RenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 
1343                Matrix4& dest, bool forGpuProgram )
1344        {
1345        Radian thetaY (fovy / 2.0f);
1346        Real tanThetaY = Math::Tan(thetaY);
1347
1348        //Real thetaX = thetaY * aspect;
1349        Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX);
1350        Real half_w = tanThetaX * nearPlane;
1351        Real half_h = tanThetaY * nearPlane;
1352        Real iw = 1.0 / half_w;
1353        Real ih = 1.0 / half_h;
1354        Real q;
1355        if (farPlane == 0)
1356        {
1357            q = 0;
1358        }
1359        else
1360        {
1361            q = 1.0 / (farPlane - nearPlane);
1362        }
1363
1364        dest = Matrix4::ZERO;
1365        dest[0][0] = iw;
1366        dest[1][1] = ih;
1367        dest[2][2] = q;
1368        dest[2][3] = -nearPlane / (farPlane - nearPlane);
1369        dest[3][3] = 1;
1370
1371        if (forGpuProgram)
1372        {
1373            dest[2][2] = -dest[2][2];
1374        }
1375        }
1376        //---------------------------------------------------------------------
1377        void D3D9RenderSystem::setAmbientLight( float r, float g, float b )
1378        {
1379                HRESULT hr = __SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( r, g, b, 1.0f ) );
1380                if( FAILED( hr ) )
1381                        OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR, 
1382                        "Failed to set render stat D3DRS_AMBIENT", "D3D9RenderSystem::setAmbientLight" );
1383        }
1384        //---------------------------------------------------------------------
1385    void D3D9RenderSystem::_useLights(const LightList& lights, unsigned short limit)
1386    {
1387        LightList::const_iterator i, iend;
1388        iend = lights.end();
1389        unsigned short num = 0;
1390        for (i = lights.begin(); i != iend && num < limit; ++i, ++num)
1391        {
1392            setD3D9Light(num, *i);
1393        }
1394        // Disable extra lights
1395        for (; num < mCurrentLights; ++num)
1396        {
1397            setD3D9Light(num, NULL);
1398        }
1399        mCurrentLights = std::min(limit, static_cast<unsigned short>(lights.size()));
1400
1401    }
1402        //---------------------------------------------------------------------
1403        void D3D9RenderSystem::setShadingType( ShadeOptions so )
1404        {
1405                HRESULT hr = __SetRenderState( D3DRS_SHADEMODE, D3D9Mappings::get(so) );
1406                if( FAILED( hr ) )
1407                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
1408                        "Failed to set render stat D3DRS_SHADEMODE", "D3D9RenderSystem::setShadingType" );
1409        }
1410        //---------------------------------------------------------------------
1411        void D3D9RenderSystem::setLightingEnabled( bool enabled )
1412        {
1413                HRESULT hr;
1414                if( FAILED( hr = __SetRenderState( D3DRS_LIGHTING, enabled ) ) )
1415                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
1416                        "Failed to set render state D3DRS_LIGHTING", "D3D9RenderSystem::setLightingEnabled" );
1417        }
1418        //---------------------------------------------------------------------
1419        void D3D9RenderSystem::setD3D9Light( size_t index, Light* lt )
1420        {
1421                HRESULT hr;
1422
1423                D3DLIGHT9 d3dLight;
1424                ZeroMemory( &d3dLight, sizeof(d3dLight) );
1425
1426        if (!lt)
1427        {
1428            if( FAILED( hr = mpD3DDevice->LightEnable( index, FALSE) ) )
1429                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
1430                                "Unable to disable light", "D3D9RenderSystem::setD3D9Light" );
1431        }
1432        else
1433        {
1434                        switch( lt->getType() )
1435                        {
1436                        case Light::LT_POINT:
1437                                d3dLight.Type = D3DLIGHT_POINT;
1438                                break;
1439
1440                        case Light::LT_DIRECTIONAL:
1441                                d3dLight.Type = D3DLIGHT_DIRECTIONAL;
1442                                break;
1443
1444                        case Light::LT_SPOTLIGHT:
1445                                d3dLight.Type = D3DLIGHT_SPOT;
1446                                d3dLight.Falloff = lt->getSpotlightFalloff();
1447                                d3dLight.Theta = lt->getSpotlightInnerAngle().valueRadians();
1448                                d3dLight.Phi = lt->getSpotlightOuterAngle().valueRadians();
1449                                break;
1450                        }
1451
1452                        ColourValue col;
1453                        col = lt->getDiffuseColour();
1454                        d3dLight.Diffuse = D3DXCOLOR( col.r, col.g, col.b, col.a );
1455
1456                        col = lt->getSpecularColour();
1457                        d3dLight.Specular = D3DXCOLOR( col.r, col.g, col.b, col.a );
1458
1459                        Vector3 vec;
1460                        if( lt->getType() != Light::LT_DIRECTIONAL )
1461                        {
1462                                vec = lt->getDerivedPosition();
1463                                d3dLight.Position = D3DXVECTOR3( vec.x, vec.y, vec.z );
1464                        }
1465                        if( lt->getType() != Light::LT_POINT )
1466                        {
1467                                vec = lt->getDerivedDirection();
1468                                d3dLight.Direction = D3DXVECTOR3( vec.x, vec.y, vec.z );
1469                        }
1470
1471                        d3dLight.Range = lt->getAttenuationRange();
1472                        d3dLight.Attenuation0 = lt->getAttenuationConstant();
1473                        d3dLight.Attenuation1 = lt->getAttenuationLinear();
1474                        d3dLight.Attenuation2 = lt->getAttenuationQuadric();
1475
1476                        if( FAILED( hr = mpD3DDevice->SetLight( index, &d3dLight ) ) )
1477                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set light details", "D3D9RenderSystem::setD3D9Light" );
1478
1479            if( FAILED( hr = mpD3DDevice->LightEnable( index, TRUE ) ) )
1480                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable light", "D3D9RenderSystem::setD3D9Light" );
1481        }
1482
1483
1484        }
1485        //---------------------------------------------------------------------
1486        void D3D9RenderSystem::_setViewMatrix( const Matrix4 &m )
1487        {
1488        // save latest view matrix
1489        mViewMatrix = m;
1490        mViewMatrix[2][0] = -mViewMatrix[2][0];
1491        mViewMatrix[2][1] = -mViewMatrix[2][1];
1492        mViewMatrix[2][2] = -mViewMatrix[2][2];
1493        mViewMatrix[2][3] = -mViewMatrix[2][3];
1494
1495        D3DXMATRIX d3dmat = D3D9Mappings::makeD3DXMatrix( mViewMatrix );
1496
1497                HRESULT hr;
1498                if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_VIEW, &d3dmat ) ) )
1499                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 view matrix", "D3D9RenderSystem::_setViewMatrix" );
1500        }
1501        //---------------------------------------------------------------------
1502        void D3D9RenderSystem::_setProjectionMatrix( const Matrix4 &m )
1503        {
1504                D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
1505
1506                if( mActiveRenderTarget->requiresTextureFlipping() )
1507        {
1508            // Invert transformed y
1509            d3dMat._12 = - d3dMat._12;
1510                        d3dMat._22 = - d3dMat._22;
1511            d3dMat._32 = - d3dMat._32;
1512            d3dMat._42 = - d3dMat._42;
1513        }
1514
1515                HRESULT hr;
1516                if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_PROJECTION, &d3dMat ) ) )
1517                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 projection matrix", "D3D9RenderSystem::_setProjectionMatrix" );
1518        }
1519        //---------------------------------------------------------------------
1520        void D3D9RenderSystem::_setWorldMatrix( const Matrix4 &m )
1521        {
1522                D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
1523
1524                HRESULT hr;
1525                if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_WORLD, &d3dMat ) ) )
1526                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 world matrix", "D3D9RenderSystem::_setWorldMatrix" );
1527        }
1528        //---------------------------------------------------------------------
1529        void D3D9RenderSystem::_setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse,
1530                const ColourValue &specular, const ColourValue &emissive, Real shininess,
1531        TrackVertexColourType tracking )
1532        {
1533               
1534                D3DMATERIAL9 material;
1535                material.Diffuse = D3DXCOLOR( diffuse.r, diffuse.g, diffuse.b, diffuse.a );
1536                material.Ambient = D3DXCOLOR( ambient.r, ambient.g, ambient.b, ambient.a );
1537                material.Specular = D3DXCOLOR( specular.r, specular.g, specular.b, specular.a );
1538                material.Emissive = D3DXCOLOR( emissive.r, emissive.g, emissive.b, emissive.a );
1539                material.Power = shininess;
1540
1541                HRESULT hr = mpD3DDevice->SetMaterial( &material );
1542                if( FAILED( hr ) )
1543                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting D3D material", "D3D9RenderSystem::_setSurfaceParams" );
1544
1545
1546                if(tracking != TVC_NONE) 
1547        {
1548            __SetRenderState(D3DRS_COLORVERTEX, TRUE);
1549            __SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, (tracking&TVC_AMBIENT)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1550            __SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (tracking&TVC_DIFFUSE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1551            __SetRenderState(D3DRS_SPECULARMATERIALSOURCE, (tracking&TVC_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1552            __SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, (tracking&TVC_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1553        } 
1554        else 
1555        {
1556            __SetRenderState(D3DRS_COLORVERTEX, FALSE);               
1557        }
1558       
1559        }
1560        //---------------------------------------------------------------------
1561        void D3D9RenderSystem::_setPointParameters(Real size, 
1562                bool attenuationEnabled, Real constant, Real linear, Real quadratic,
1563                Real minSize, Real maxSize)
1564    {
1565                if(attenuationEnabled)
1566                {
1567                        // scaling required
1568                        __SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
1569                        __SetFloatRenderState(D3DRS_POINTSCALE_A, constant);
1570                        __SetFloatRenderState(D3DRS_POINTSCALE_B, linear);
1571                        __SetFloatRenderState(D3DRS_POINTSCALE_C, quadratic);
1572                }
1573                else
1574                {
1575                        // no scaling required
1576                        __SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
1577                }
1578                __SetFloatRenderState(D3DRS_POINTSIZE, size);
1579                __SetFloatRenderState(D3DRS_POINTSIZE_MIN, minSize);
1580                if (maxSize == 0.0f)
1581                        maxSize = mCapabilities->getMaxPointSize();
1582                __SetFloatRenderState(D3DRS_POINTSIZE_MAX, maxSize);
1583
1584
1585    }
1586        //---------------------------------------------------------------------
1587        void D3D9RenderSystem::_setPointSpritesEnabled(bool enabled)
1588        {
1589                if (enabled)
1590                {
1591                        __SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
1592                }
1593                else
1594                {
1595                        __SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
1596                }
1597        }
1598        //---------------------------------------------------------------------
1599        void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const TexturePtr& tex )
1600        {
1601                HRESULT hr;
1602                D3D9TexturePtr dt = tex;
1603                if (enabled && !dt.isNull())
1604                {
1605            // note used
1606            dt->touch();
1607
1608                        IDirect3DBaseTexture9 *pTex = dt->getTexture();
1609                        if (mTexStageDesc[stage].pTex != pTex)
1610                        {
1611                                hr = mpD3DDevice->SetTexture(stage, pTex);
1612                                if( hr != S_OK )
1613                                {
1614                                        String str = "Unable to set texture '" + tex->getName() + "' in D3D9";
1615                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1616                                }
1617                               
1618                                // set stage desc.
1619                                mTexStageDesc[stage].pTex = pTex;
1620                                mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
1621                        }
1622                }
1623                else
1624                {
1625                        if (mTexStageDesc[stage].pTex != 0)
1626                        {
1627                                hr = mpD3DDevice->SetTexture(stage, 0);
1628                                if( hr != S_OK )
1629                                {
1630                                        String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9";
1631                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1632                                }
1633                        }
1634
1635                        hr = this->__SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
1636                        if( hr != S_OK )
1637                        {
1638                                String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9";
1639                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1640                        }
1641
1642                        // set stage desc. to defaults
1643                        mTexStageDesc[stage].pTex = 0;
1644                        mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
1645                        mTexStageDesc[stage].coordIndex = 0;
1646                        mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
1647                }
1648        }
1649        //---------------------------------------------------------------------
1650        void D3D9RenderSystem::_setVertexTexture(size_t stage, const TexturePtr& tex)
1651        {
1652                if (tex.isNull())
1653                {
1654
1655                        if (mTexStageDesc[stage].pVertexTex != 0)
1656                        {
1657                                HRESULT hr = mpD3DDevice->SetTexture(D3DVERTEXTEXTURESAMPLER0 + stage, 0);
1658                                if( hr != S_OK )
1659                                {
1660                                        String str = "Unable to disable vertex texture '" 
1661                                                + StringConverter::toString(stage) + "' in D3D9";
1662                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" );
1663                                }
1664                        }
1665
1666                        // set stage desc. to defaults
1667                        mTexStageDesc[stage].pVertexTex = 0;
1668                }
1669                else
1670                {
1671                        D3D9TexturePtr dt = tex;
1672                        // note used
1673                        dt->touch();
1674
1675                        IDirect3DBaseTexture9 *pTex = dt->getTexture();
1676                        if (mTexStageDesc[stage].pVertexTex != pTex)
1677                        {
1678                                HRESULT hr = mpD3DDevice->SetTexture(D3DVERTEXTEXTURESAMPLER0 + stage, pTex);
1679                                if( hr != S_OK )
1680                                {
1681                                        String str = "Unable to set vertex texture '" + tex->getName() + "' in D3D9";
1682                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" );
1683                                }
1684
1685                                // set stage desc.
1686                                mTexStageDesc[stage].pVertexTex = pTex;
1687                        }
1688
1689                }
1690
1691        }
1692        //---------------------------------------------------------------------
1693        void D3D9RenderSystem::_disableTextureUnit(size_t texUnit)
1694        {
1695                RenderSystem::_disableTextureUnit(texUnit);
1696                // also disable vertex texture unit
1697                static TexturePtr nullPtr;
1698                _setVertexTexture(texUnit, nullPtr);
1699        }
1700        //---------------------------------------------------------------------
1701        void D3D9RenderSystem::_setTextureCoordSet( size_t stage, size_t index )
1702        {
1703                HRESULT hr;
1704        // Record settings
1705        mTexStageDesc[stage].coordIndex = index;
1706
1707                hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(mTexStageDesc[stage].autoTexCoordType, mCaps) | index );
1708                if( FAILED( hr ) )
1709                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. set index", "D3D9RenderSystem::_setTextureCoordSet" );
1710        }
1711        //---------------------------------------------------------------------
1712        void D3D9RenderSystem::_setTextureCoordCalculation( size_t stage, TexCoordCalcMethod m,
1713        const Frustum* frustum)
1714        {
1715                HRESULT hr;
1716                // record the stage state
1717                mTexStageDesc[stage].autoTexCoordType = m;
1718        mTexStageDesc[stage].frustum = frustum;
1719
1720                hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(m, mCaps) | mTexStageDesc[stage].coordIndex );
1721                if(FAILED(hr))
1722                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture auto tex.coord. generation mode", "D3D9RenderSystem::_setTextureCoordCalculation" );
1723        }
1724        //---------------------------------------------------------------------
1725        void D3D9RenderSystem::_setTextureMipmapBias(size_t unit, float bias)
1726        {
1727                if (mCapabilities->hasCapability(RSC_MIPMAP_LOD_BIAS))
1728                {
1729                        // ugh - have to pass float data through DWORD with no conversion
1730                        HRESULT hr = __SetSamplerState(unit, D3DSAMP_MIPMAPLODBIAS, 
1731                                *(DWORD*)&bias);
1732                        if(FAILED(hr))
1733                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture mipmap bias", 
1734                                "D3D9RenderSystem::_setTextureMipmapBias" );
1735
1736                }
1737        }
1738        //---------------------------------------------------------------------
1739        void D3D9RenderSystem::_setTextureMatrix( size_t stage, const Matrix4& xForm )
1740        {
1741                HRESULT hr;
1742                D3DXMATRIX d3dMat; // the matrix we'll maybe apply
1743                Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format
1744                // Cache texcoord calc method to register
1745                TexCoordCalcMethod autoTexCoordType = mTexStageDesc[stage].autoTexCoordType;
1746
1747                if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP)
1748        {
1749            if (mCaps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP)
1750            {
1751                /** Invert the texture for the spheremap */
1752                Matrix4 ogreMatEnvMap = Matrix4::IDENTITY;
1753                            // set env_map values
1754                            ogreMatEnvMap[1][1] = -1.0f;
1755                            // concatenate with the xForm
1756                            newMat = newMat.concatenate(ogreMatEnvMap);
1757            }
1758            else
1759            {
1760                        /* If envmap is applied, but device doesn't support spheremap,
1761                        then we have to use texture transform to make the camera space normal
1762                        reference the envmap properly. This isn't exactly the same as spheremap
1763                        (it looks nasty on flat areas because the camera space normals are the same)
1764                        but it's the best approximation we have in the absence of a proper spheremap */
1765                            // concatenate with the xForm
1766                newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE);
1767            }
1768                }
1769
1770        // If this is a cubic reflection, we need to modify using the view matrix
1771        if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION)
1772        {
1773            // Get transposed 3x3
1774            // We want to transpose since that will invert an orthonormal matrix ie rotation
1775            Matrix4 ogreViewTransposed;
1776            ogreViewTransposed[0][0] = mViewMatrix[0][0];
1777            ogreViewTransposed[0][1] = mViewMatrix[1][0];
1778            ogreViewTransposed[0][2] = mViewMatrix[2][0];
1779            ogreViewTransposed[0][3] = 0.0f;
1780
1781            ogreViewTransposed[1][0] = mViewMatrix[0][1];
1782            ogreViewTransposed[1][1] = mViewMatrix[1][1];
1783            ogreViewTransposed[1][2] = mViewMatrix[2][1];
1784            ogreViewTransposed[1][3] = 0.0f;
1785
1786            ogreViewTransposed[2][0] = mViewMatrix[0][2];
1787            ogreViewTransposed[2][1] = mViewMatrix[1][2];
1788            ogreViewTransposed[2][2] = mViewMatrix[2][2];
1789            ogreViewTransposed[2][3] = 0.0f;
1790
1791            ogreViewTransposed[3][0] = 0.0f;
1792            ogreViewTransposed[3][1] = 0.0f;
1793            ogreViewTransposed[3][2] = 0.0f;
1794            ogreViewTransposed[3][3] = 1.0f;
1795           
1796            newMat = newMat.concatenate(ogreViewTransposed);
1797        }
1798
1799        if (autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
1800        {
1801            // Derive camera space to projector space transform
1802            // To do this, we need to undo the camera view matrix, then
1803            // apply the projector view & projection matrices
1804            newMat = mViewMatrix.inverse();
1805            newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat;
1806            newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat;
1807            newMat = Matrix4::CLIPSPACE2DTOIMAGESPACE * newMat;
1808            newMat = xForm * newMat;
1809        }
1810
1811                // need this if texture is a cube map, to invert D3D's z coord
1812                if (autoTexCoordType != TEXCALC_NONE &&
1813            autoTexCoordType != TEXCALC_PROJECTIVE_TEXTURE)
1814                {
1815            newMat[2][0] = -newMat[2][0];
1816            newMat[2][1] = -newMat[2][1];
1817            newMat[2][2] = -newMat[2][2];
1818            newMat[2][3] = -newMat[2][3];
1819                }
1820
1821        // convert our matrix to D3D format
1822                d3dMat = D3D9Mappings::makeD3DXMatrix(newMat);
1823
1824                // set the matrix if it's not the identity
1825                if (!D3DXMatrixIsIdentity(&d3dMat))
1826                {
1827            /* It's seems D3D automatically add a texture coordinate with value 1,
1828            and fill up the remaining texture coordinates with 0 for the input
1829            texture coordinates before pass to texture coordinate transformation.
1830
1831               NOTE: It's difference with D3DDECLTYPE enumerated type expand in
1832            DirectX SDK documentation!
1833
1834               So we should prepare the texcoord transform, make the transformation
1835            just like standardized vector expand, thus, fill w with value 1 and
1836            others with 0.
1837            */
1838            if (autoTexCoordType == TEXCALC_NONE)
1839            {
1840                /* FIXME: The actually input texture coordinate dimensions should
1841                be determine by texture coordinate vertex element. Now, just trust
1842                user supplied texture type matchs texture coordinate vertex element.
1843                */
1844                if (mTexStageDesc[stage].texType == D3D9Mappings::D3D_TEX_TYPE_NORMAL)
1845                {
1846                    /* It's 2D input texture coordinate:
1847
1848                      texcoord in vertex buffer     D3D expanded to     We are adjusted to
1849                                                -->                 -->
1850                                (u, v)               (u, v, 1, 0)          (u, v, 0, 1)
1851                    */
1852                    std::swap(d3dMat._31, d3dMat._41);
1853                    std::swap(d3dMat._32, d3dMat._42);
1854                    std::swap(d3dMat._33, d3dMat._43);
1855                    std::swap(d3dMat._34, d3dMat._44);
1856                }
1857            }
1858            else
1859            {
1860                // All texgen generate 3D input texture coordinates.
1861            }
1862
1863                        // tell D3D the dimension of tex. coord.
1864                        int texCoordDim = D3DTTFF_COUNT2;
1865            if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
1866            {
1867                /* We want texcoords (u, v, w, q) always get divided by q, but D3D
1868                projected texcoords is divided by the last element (in the case of
1869                2D texcoord, is w). So we tweak the transform matrix, transform the
1870                texcoords with w and q swapped: (u, v, q, w), and then D3D will
1871                divide u, v by q. The w and q just ignored as it wasn't used by
1872                rasterizer.
1873                */
1874                            switch (mTexStageDesc[stage].texType)
1875                            {
1876                            case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
1877                    std::swap(d3dMat._13, d3dMat._14);
1878                    std::swap(d3dMat._23, d3dMat._24);
1879                    std::swap(d3dMat._33, d3dMat._34);
1880                    std::swap(d3dMat._43, d3dMat._44);
1881
1882                    texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3;
1883                    break;
1884
1885                            case D3D9Mappings::D3D_TEX_TYPE_CUBE:
1886                            case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
1887                    // Yes, we support 3D projective texture.
1888                                    texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT4;
1889                    break;
1890                }
1891            }
1892            else
1893            {
1894                            switch (mTexStageDesc[stage].texType)
1895                            {
1896                            case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
1897                                    texCoordDim = D3DTTFF_COUNT2;
1898                                    break;
1899                            case D3D9Mappings::D3D_TEX_TYPE_CUBE:
1900                            case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
1901                                    texCoordDim = D3DTTFF_COUNT3;
1902                    break;
1903                            }
1904            }
1905
1906                        hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim );
1907                        if (FAILED(hr))
1908                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" );
1909
1910                        hr = mpD3DDevice->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
1911                        if (FAILED(hr))
1912                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
1913                }
1914                else
1915                {
1916                        // disable all of this
1917                        hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
1918                        if( FAILED( hr ) )
1919                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable texture coordinate transform", "D3D9RenderSystem::_setTextureMatrix" );
1920
1921                        // Needless to sets texture transform here, it's never used at all
1922                }
1923        }
1924        //---------------------------------------------------------------------
1925        void D3D9RenderSystem::_setTextureAddressingMode( size_t stage, 
1926                const TextureUnitState::UVWAddressingMode& uvw )
1927        {
1928                HRESULT hr;
1929                if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSU, D3D9Mappings::get(uvw.u, mCaps) ) ) )
1930                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for U", "D3D9RenderSystem::_setTextureAddressingMode" );
1931                if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSV, D3D9Mappings::get(uvw.v, mCaps) ) ) )
1932                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for V", "D3D9RenderSystem::_setTextureAddressingMode" );
1933                if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSW, D3D9Mappings::get(uvw.w, mCaps) ) ) )
1934                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for W", "D3D9RenderSystem::_setTextureAddressingMode" );
1935        }
1936    //-----------------------------------------------------------------------------
1937    void D3D9RenderSystem::_setTextureBorderColour(size_t stage,
1938        const ColourValue& colour)
1939    {
1940                HRESULT hr;
1941                if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_BORDERCOLOR, colour.getAsARGB()) ) )
1942                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture border colour", "D3D9RenderSystem::_setTextureBorderColour" );
1943    }
1944        //---------------------------------------------------------------------
1945        void D3D9RenderSystem::_setTextureBlendMode( size_t stage, const LayerBlendModeEx& bm )
1946        {
1947                HRESULT hr = S_OK;
1948                D3DTEXTURESTAGESTATETYPE tss;
1949                D3DCOLOR manualD3D;
1950
1951                // choose type of blend.
1952                if( bm.blendType == LBT_COLOUR )
1953                        tss = D3DTSS_COLOROP;
1954                else if( bm.blendType == LBT_ALPHA )
1955                        tss = D3DTSS_ALPHAOP;
1956                else
1957                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
1958                        "Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
1959
1960                // set manual factor if required by operation
1961                if (bm.operation == LBX_BLEND_MANUAL)
1962                {
1963                        hr = __SetRenderState( D3DRS_TEXTUREFACTOR, D3DXCOLOR(0.0, 0.0, 0.0,  bm.factor) );
1964                        if (FAILED(hr))
1965                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
1966                }
1967                // set operation
1968                hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.operation, mCaps) );
1969                if (FAILED(hr))
1970                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set operation", "D3D9RenderSystem::_setTextureBlendMode" );
1971
1972                // choose source 1
1973                if( bm.blendType == LBT_COLOUR )
1974                {
1975                        tss = D3DTSS_COLORARG1;
1976                        manualD3D = D3DXCOLOR( bm.colourArg1.r, bm.colourArg1.g, bm.colourArg1.b, bm.colourArg1.a );
1977                        mManualBlendColours[stage][0] = bm.colourArg1;
1978                }
1979                else if( bm.blendType == LBT_ALPHA )
1980                {
1981                        tss = D3DTSS_ALPHAARG1;
1982                        manualD3D = D3DXCOLOR( mManualBlendColours[stage][0].r, 
1983                                mManualBlendColours[stage][0].g, 
1984                                mManualBlendColours[stage][0].b, bm.alphaArg1 );
1985                }
1986                else
1987                {
1988                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 
1989                                "Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
1990                }
1991                // Set manual factor if required
1992                if (bm.source1 == LBS_MANUAL)
1993                {
1994                        if (mPerStageConstantSupport)
1995                        {
1996                                // Per-stage state
1997                                hr = __SetTextureStageState(stage, D3DTSS_CONSTANT, manualD3D);
1998                        }
1999                        else
2000                        {
2001                                // Global state
2002                                hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
2003                        }
2004                        if (FAILED(hr))
2005                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
2006                }
2007                // set source 1
2008                hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source1, mPerStageConstantSupport) );
2009                if (FAILED(hr))
2010                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source1", "D3D9RenderSystem::_setTextureBlendMode" );
2011               
2012                // choose source 2
2013                if( bm.blendType == LBT_COLOUR )
2014                {
2015                        tss = D3DTSS_COLORARG2;
2016                        manualD3D = D3DXCOLOR( bm.colourArg2.r, bm.colourArg2.g, bm.colourArg2.b, bm.colourArg2.a );
2017                        mManualBlendColours[stage][1] = bm.colourArg1;
2018                }
2019                else if( bm.blendType == LBT_ALPHA )
2020                {
2021                        tss = D3DTSS_ALPHAARG2;
2022                        manualD3D = D3DXCOLOR( mManualBlendColours[stage][1].r, 
2023                                mManualBlendColours[stage][1].g, 
2024                                mManualBlendColours[stage][1].b, 
2025                                bm.alphaArg2 );
2026                }
2027                // Set manual factor if required
2028                if (bm.source2 == LBS_MANUAL)
2029                {
2030                        if (mPerStageConstantSupport)
2031                        {
2032                                // Per-stage state
2033                                hr = __SetTextureStageState(stage, D3DTSS_CONSTANT, manualD3D);
2034                        }
2035                        else
2036                        {
2037                                hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
2038                        }
2039                        if (FAILED(hr))
2040                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
2041                }
2042                // Now set source 2
2043                hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source2, mPerStageConstantSupport) );
2044                if (FAILED(hr))
2045                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source 2", "D3D9RenderSystem::_setTextureBlendMode" );
2046
2047                // Set interpolation factor if lerping
2048                if (bm.operation == LBX_BLEND_DIFFUSE_COLOUR && 
2049                        mCaps.TextureOpCaps & D3DTEXOPCAPS_LERP)
2050                {
2051                        // choose source 0 (lerp factor)
2052                        if( bm.blendType == LBT_COLOUR )
2053                        {
2054                                tss = D3DTSS_COLORARG0;
2055                        }
2056                        else if( bm.blendType == LBT_ALPHA )
2057                        {
2058                                tss = D3DTSS_ALPHAARG0;
2059                        }
2060                        hr = __SetTextureStageState(stage, tss, D3DTA_DIFFUSE);
2061
2062                        if (FAILED(hr))
2063                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set lerp source 0", 
2064                                        "D3D9RenderSystem::_setTextureBlendMode" );
2065
2066                }
2067        }
2068        //---------------------------------------------------------------------
2069        void D3D9RenderSystem::_setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor )
2070        {
2071                HRESULT hr;
2072                if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO)
2073                {
2074                        if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
2075                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2076                }
2077                else
2078                {
2079                        if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
2080                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2081                        if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
2082                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source blend", "D3D9RenderSystem::_setSceneBlending" );
2083                        if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
2084                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set destination blend", "D3D9RenderSystem::_setSceneBlending" );
2085                }
2086        }
2087        //---------------------------------------------------------------------
2088        void D3D9RenderSystem::_setAlphaRejectSettings( CompareFunction func, unsigned char value )
2089        {
2090                HRESULT hr;
2091        if (func != CMPF_ALWAYS_PASS)
2092        {
2093            if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE ) ) )
2094                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to enable alpha testing", 
2095                "D3D9RenderSystem::_setAlphaRejectSettings" );
2096        }
2097        else
2098        {
2099            if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE ) ) )
2100                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to disable alpha testing", 
2101                "D3D9RenderSystem::_setAlphaRejectSettings" );
2102        }
2103        // Set always just be sure
2104                if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) )
2105                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha reject function", "D3D9RenderSystem::_setAlphaRejectSettings" );
2106                if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) )
2107                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set render state D3DRS_ALPHAREF", "D3D9RenderSystem::_setAlphaRejectSettings" );
2108        }
2109        //---------------------------------------------------------------------
2110        void D3D9RenderSystem::_setCullingMode( CullingMode mode )
2111        {
2112                HRESULT hr;
2113        bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
2114                (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding));
2115
2116                if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE, 
2117            D3D9Mappings::get(mode, flip))) )
2118                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set culling mode", "D3D9RenderSystem::_setCullingMode" );
2119        }
2120        //---------------------------------------------------------------------
2121        void D3D9RenderSystem::_setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction )
2122        {
2123                _setDepthBufferCheckEnabled( depthTest );
2124                _setDepthBufferWriteEnabled( depthWrite );
2125                _setDepthBufferFunction( depthFunction );
2126        }
2127        //---------------------------------------------------------------------
2128        void D3D9RenderSystem::_setDepthBufferCheckEnabled( bool enabled )
2129        {
2130                HRESULT hr;
2131
2132                if( enabled )
2133                {
2134                        // Use w-buffer if available and enabled
2135                        if( mWBuffer && mCaps.RasterCaps & D3DPRASTERCAPS_WBUFFER )
2136                                hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
2137                        else
2138                                hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
2139                }
2140                else
2141                        hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
2142
2143                if( FAILED( hr ) )
2144                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test state", "D3D9RenderSystem::_setDepthBufferCheckEnabled" );
2145        }
2146        //---------------------------------------------------------------------
2147        void D3D9RenderSystem::_setDepthBufferWriteEnabled( bool enabled )
2148        {
2149                HRESULT hr;
2150
2151                if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) )
2152                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer write state", "D3D9RenderSystem::_setDepthBufferWriteEnabled" );
2153        }
2154        //---------------------------------------------------------------------
2155        void D3D9RenderSystem::_setDepthBufferFunction( CompareFunction func )
2156        {
2157                HRESULT hr;
2158                if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) )
2159                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test function", "D3D9RenderSystem::_setDepthBufferFunction" );
2160        }
2161        //---------------------------------------------------------------------
2162        void D3D9RenderSystem::_setDepthBias(float constantBias, float slopeScaleBias)
2163        {
2164       
2165                if ((mCaps.RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
2166                {
2167                        // Negate bias since D3D is backward
2168                        // D3D also expresses the constant bias as an absolute value, rather than
2169                        // relative to minimum depth unit, so scale to fit
2170                        constantBias = -constantBias / 250000.0f;
2171                        HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, FLOAT2DWORD(constantBias));
2172                        if (FAILED(hr))
2173                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting constant depth bias", 
2174                                "D3D9RenderSystem::_setDepthBias");
2175                }
2176
2177                if ((mCaps.RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
2178                {
2179                        // Negate bias since D3D is backward
2180                        slopeScaleBias = -slopeScaleBias;
2181                        HRESULT hr = __SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, FLOAT2DWORD(slopeScaleBias));
2182                        if (FAILED(hr))
2183                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting slope scale depth bias", 
2184                                "D3D9RenderSystem::_setDepthBias");
2185                }
2186
2187
2188        }
2189        //---------------------------------------------------------------------
2190        void D3D9RenderSystem::_setColourBufferWriteEnabled(bool red, bool green, 
2191                bool blue, bool alpha)
2192        {
2193                DWORD val = 0;
2194                if (red) 
2195                        val |= D3DCOLORWRITEENABLE_RED;
2196                if (green)
2197                        val |= D3DCOLORWRITEENABLE_GREEN;
2198                if (blue)
2199                        val |= D3DCOLORWRITEENABLE_BLUE;
2200                if (alpha)
2201                        val |= D3DCOLORWRITEENABLE_ALPHA;
2202                HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val); 
2203                if (FAILED(hr))
2204                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting colour write enable flags", 
2205                        "D3D9RenderSystem::_setColourBufferWriteEnabled");
2206        }
2207        //---------------------------------------------------------------------
2208        void D3D9RenderSystem::_setFog( FogMode mode, const ColourValue& colour, Real densitiy, Real start, Real end )
2209        {
2210                HRESULT hr;
2211
2212                D3DRENDERSTATETYPE fogType, fogTypeNot;
2213
2214                if (mCaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE)
2215                {
2216                        fogType = D3DRS_FOGTABLEMODE;
2217                        fogTypeNot = D3DRS_FOGVERTEXMODE;
2218                }
2219                else
2220                {
2221                        fogType = D3DRS_FOGVERTEXMODE;
2222                        fogTypeNot = D3DRS_FOGTABLEMODE;
2223                }
2224
2225                if( mode == FOG_NONE)
2226                {
2227                        // just disable
2228                        hr = __SetRenderState(fogType, D3DFOG_NONE );
2229                        hr = __SetRenderState(D3DRS_FOGENABLE, FALSE);
2230                }
2231                else
2232                {
2233                        // Allow fog
2234                        hr = __SetRenderState( D3DRS_FOGENABLE, TRUE );
2235                        hr = __SetRenderState( fogTypeNot, D3DFOG_NONE );
2236                        hr = __SetRenderState( fogType, D3D9Mappings::get(mode) );
2237
2238                        hr = __SetRenderState( D3DRS_FOGCOLOR, colour.getAsARGB() );
2239                        hr = __SetFloatRenderState( D3DRS_FOGSTART, start );
2240                        hr = __SetFloatRenderState( D3DRS_FOGEND, end );
2241                        hr = __SetFloatRenderState( D3DRS_FOGDENSITY, densitiy );
2242                }
2243
2244                if( FAILED( hr ) )
2245                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting render state", "D3D9RenderSystem::_setFog" );
2246        }
2247        //---------------------------------------------------------------------
2248        void D3D9RenderSystem::_setPolygonMode(PolygonMode level)
2249        {
2250                HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level));
2251                if (FAILED(hr))
2252                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting polygon mode.", "D3D9RenderSystem::setPolygonMode");
2253        }
2254        //---------------------------------------------------------------------
2255        void D3D9RenderSystem::setStencilCheckEnabled(bool enabled)
2256        {
2257                // Allow stencilling
2258                HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled);
2259                if (FAILED(hr))
2260                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error enabling / disabling stencilling.",
2261                        "D3D9RenderSystem::setStencilCheckEnabled");
2262        }
2263    //---------------------------------------------------------------------
2264    void D3D9RenderSystem::setStencilBufferParams(CompareFunction func, 
2265        uint32 refValue, uint32 mask, StencilOperation stencilFailOp, 
2266        StencilOperation depthFailOp, StencilOperation passOp, 
2267        bool twoSidedOperation)
2268    {
2269        HRESULT hr;
2270        bool flip;
2271
2272        // 2-sided operation
2273        if (twoSidedOperation)
2274        {
2275            if (!mCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL))
2276                OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "2-sided stencils are not supported",
2277                    "D3D9RenderSystem::setStencilBufferParams");
2278            hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
2279                    if (FAILED(hr))
2280                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 2-sided stencil mode.",
2281                            "D3D9RenderSystem::setStencilBufferParams");
2282            // NB: We should always treat CCW as front face for consistent with default
2283            // culling mode. Therefore, we must take care with two-sided stencil settings.
2284            flip = (mInvertVertexWinding && mActiveRenderTarget->requiresTextureFlipping()) ||
2285                   (!mInvertVertexWinding && !mActiveRenderTarget->requiresTextureFlipping());
2286
2287            // Set alternative versions of ops
2288            // fail op
2289            hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, !flip));
2290            if (FAILED(hr))
2291                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation (2-sided).",
2292                "D3D9RenderSystem::setStencilBufferParams");
2293
2294            // depth fail op
2295            hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, !flip));
2296            if (FAILED(hr))
2297                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation (2-sided).",
2298                "D3D9RenderSystem::setStencilBufferParams");
2299
2300            // pass op
2301            hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, !flip));
2302            if (FAILED(hr))
2303                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation (2-sided).",
2304                "D3D9RenderSystem::setStencilBufferParams");
2305        }
2306        else
2307        {
2308            hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
2309                    if (FAILED(hr))
2310                            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 1-sided stencil mode.",
2311                            "D3D9RenderSystem::setStencilBufferParams");
2312            flip = false;
2313        }
2314
2315        // func
2316        hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func));
2317                if (FAILED(hr))
2318                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer test function.",
2319                        "D3D9RenderSystem::setStencilBufferParams");
2320
2321        // reference value
2322        hr = __SetRenderState(D3DRS_STENCILREF, refValue);
2323                if (FAILED(hr))
2324                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer reference value.",
2325                        "D3D9RenderSystem::setStencilBufferParams");
2326
2327        // mask
2328        hr = __SetRenderState(D3DRS_STENCILMASK, mask);
2329                if (FAILED(hr))
2330                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer mask.",
2331                        "D3D9RenderSystem::setStencilBufferParams");
2332
2333                // fail op
2334        hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp, flip));
2335                if (FAILED(hr))
2336                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation.",
2337                        "D3D9RenderSystem::setStencilBufferParams");
2338
2339        // depth fail op
2340        hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp, flip));
2341                if (FAILED(hr))
2342                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation.",
2343                        "D3D9RenderSystem::setStencilBufferParams");
2344
2345        // pass op
2346        hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp, flip));
2347                if (FAILED(hr))
2348                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation.",
2349                        "D3D9RenderSystem::setStencilBufferParams");
2350        }
2351        //---------------------------------------------------------------------
2352    void D3D9RenderSystem::_setTextureUnitFiltering(size_t unit, FilterType ftype, 
2353        FilterOptions filter)
2354        {
2355                HRESULT hr;
2356                D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType;
2357        hr = __SetSamplerState( unit, D3D9Mappings::get(ftype), 
2358            D3D9Mappings::get(ftype, filter, mCaps, texType));
2359                if (FAILED(hr))
2360                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture filter ", "D3D9RenderSystem::_setTextureUnitFiltering");
2361        }
2362    //---------------------------------------------------------------------
2363        DWORD D3D9RenderSystem::_getCurrentAnisotropy(size_t unit)
2364        {
2365                DWORD oldVal;
2366                mpD3DDevice->GetSamplerState(unit, D3DSAMP_MAXANISOTROPY, &oldVal);
2367                        return oldVal;
2368        }
2369        //---------------------------------------------------------------------
2370        void D3D9RenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy)
2371        {
2372                if ((DWORD)maxAnisotropy > mCaps.MaxAnisotropy)
2373                        maxAnisotropy = mCaps.MaxAnisotropy;
2374
2375                if (_getCurrentAnisotropy(unit) != maxAnisotropy)
2376                        __SetSamplerState( unit, D3DSAMP_MAXANISOTROPY, maxAnisotropy );
2377        }
2378        //---------------------------------------------------------------------
2379        HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
2380        {
2381                HRESULT hr;
2382                DWORD oldVal;
2383
2384                if ( FAILED( hr = mpD3DDevice->GetRenderState(state, &oldVal) ) )
2385                        return hr;
2386                if ( oldVal == value )
2387                        return D3D_OK;
2388                else
2389                        return mpD3DDevice->SetRenderState(state, value);
2390        }
2391        //---------------------------------------------------------------------
2392        HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
2393        {
2394                HRESULT hr;
2395                DWORD oldVal;
2396
2397                if ( FAILED( hr = mpD3DDevice->GetSamplerState(sampler, type, &oldVal) ) )
2398                        return hr;
2399                if ( oldVal == value )
2400                        return D3D_OK;
2401                else
2402                        return mpD3DDevice->SetSamplerState(sampler, type, value);
2403        }
2404        //---------------------------------------------------------------------
2405        HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
2406        {
2407                HRESULT hr;
2408                DWORD oldVal;
2409               
2410                if ( FAILED( hr = mpD3DDevice->GetTextureStageState(stage, type, &oldVal) ) )
2411                        return hr;
2412                if ( oldVal == value )
2413                        return D3D_OK;
2414                else
2415                        return mpD3DDevice->SetTextureStageState(stage, type, value);
2416        }
2417        //---------------------------------------------------------------------
2418        void D3D9RenderSystem::_setViewport( Viewport *vp )
2419        {
2420                if( vp != mActiveViewport || vp->_isUpdated() )
2421                {
2422                        mActiveViewport = vp;
2423                        mActiveRenderTarget = vp->getTarget();
2424
2425                        // ok, it's different, time to set render target and viewport params
2426                        D3DVIEWPORT9 d3dvp;
2427                        HRESULT hr;
2428
2429                        // Set render target
2430                        RenderTarget* target;
2431                        target = vp->getTarget();
2432
2433                        // Retrieve render surfaces (up to OGRE_MAX_MULTIPLE_RENDER_TARGETS)
2434                        LPDIRECT3DSURFACE9 pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS];
2435                        memset(pBack, 0, sizeof(pBack));
2436                        target->getCustomAttribute( "DDBACKBUFFER", &pBack );
2437                        if (!pBack[0])
2438                                return;
2439
2440                        LPDIRECT3DSURFACE9 pDepth = NULL;
2441                        target->getCustomAttribute( "D3DZBUFFER", &pDepth );
2442                        if (!pDepth)
2443                        {
2444                                /// No depth buffer provided, use our own
2445                                /// Request a depth stencil that is compatible with the format, multisample type and
2446                                /// dimensions of the render target.
2447                                D3DSURFACE_DESC srfDesc;
2448                                if(FAILED(pBack[0]->GetDesc(&srfDesc)))
2449                                        return; // ?
2450                                pDepth = _getDepthStencilFor(srfDesc.Format, srfDesc.MultiSampleType, srfDesc.Width, srfDesc.Height);
2451                        }
2452                        // Bind render targets
2453                        uint count = mCapabilities->numMultiRenderTargets();
2454                        for(uint x=0; x<count; ++x)
2455                        {
2456                                hr = mpD3DDevice->SetRenderTarget(x, pBack[x]);
2457                                if (FAILED(hr))
2458                                {
2459                                        String msg = DXGetErrorDescription9(hr);
2460                                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setRenderTarget : " + msg, "D3D9RenderSystem::_setViewport" );
2461                                }
2462                        }
2463                        hr = mpD3DDevice->SetDepthStencilSurface(pDepth);
2464                        if (FAILED(hr))
2465                        {
2466                                String msg = DXGetErrorDescription9(hr);
2467                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setDepthStencil : " + msg, "D3D9RenderSystem::_setViewport" );
2468                        }
2469
2470                        _setCullingMode( mCullingMode );
2471
2472                        // set viewport dimensions
2473                        d3dvp.X = vp->getActualLeft();
2474                        d3dvp.Y = vp->getActualTop();
2475                        d3dvp.Width = vp->getActualWidth();
2476                        d3dvp.Height = vp->getActualHeight();
2477            if (target->requiresTextureFlipping())
2478            {
2479                // Convert "top-left" to "bottom-left"
2480                d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
2481            }
2482
2483                        // Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
2484                        d3dvp.MinZ = 0.0f;
2485                        d3dvp.MaxZ = 1.0f;
2486
2487                        if( FAILED( hr = mpD3DDevice->SetViewport( &d3dvp ) ) )
2488                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set viewport.", "D3D9RenderSystem::_setViewport" );
2489
2490                        vp->_clearUpdatedFlag();
2491                }
2492        }
2493        //---------------------------------------------------------------------
2494        void D3D9RenderSystem::_beginFrame()
2495        {
2496                HRESULT hr;
2497
2498                if( !mActiveViewport )
2499                        OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Cannot begin frame - no viewport selected.", "D3D9RenderSystem::_beginFrame" );
2500
2501                if( FAILED( hr = mpD3DDevice->BeginScene() ) )
2502                {
2503                        String msg = DXGetErrorDescription9(hr);
2504                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error beginning frame :" + msg, "D3D9RenderSystem::_beginFrame" );
2505                }
2506
2507                if(!mBasicStatesInitialised)
2508                {
2509                        // First-time
2510                        // setup some defaults
2511                        // Allow specular
2512                        hr = __SetRenderState(D3DRS_SPECULARENABLE, TRUE);
2513                        if (FAILED(hr))
2514                        {
2515                                String msg = DXGetErrorDescription9(hr);
2516                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error enabling alpha blending option : " + msg, "D3D9RenderSystem::_beginFrame");
2517                        }
2518                        mBasicStatesInitialised = true;
2519                }
2520
2521        }
2522        //---------------------------------------------------------------------
2523        void D3D9RenderSystem::_endFrame()
2524        {
2525
2526                HRESULT hr;
2527                if( FAILED( hr = mpD3DDevice->EndScene() ) )
2528                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error ending frame", "D3D9RenderSystem::_endFrame" );
2529
2530        }
2531        //---------------------------------------------------------------------
2532        inline bool D3D9RenderSystem::compareDecls( D3DVERTEXELEMENT9* pDecl1, D3DVERTEXELEMENT9* pDecl2, size_t size )
2533        {
2534                for( size_t i=0; i < size; i++ )
2535                {
2536                        if( pDecl1[i].Method != pDecl2[i].Method ||
2537                                pDecl1[i].Offset != pDecl2[i].Offset ||
2538                                pDecl1[i].Stream != pDecl2[i].Stream ||
2539                                pDecl1[i].Type != pDecl2[i].Type ||
2540                                pDecl1[i].Usage != pDecl2[i].Usage ||
2541                                pDecl1[i].UsageIndex != pDecl2[i].UsageIndex)
2542                        {
2543                                return false;
2544                        }
2545                }
2546
2547                return true;
2548        }
2549    //---------------------------------------------------------------------
2550        void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl)
2551        {
2552        HRESULT hr;
2553
2554        D3D9VertexDeclaration* d3ddecl = 
2555            static_cast<D3D9VertexDeclaration*>(decl);
2556
2557        if (FAILED(hr = mpD3DDevice->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration())))
2558        {
2559            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 vertex declaration", 
2560                "D3D9RenderSystem::setVertexDeclaration");
2561        }
2562
2563        }
2564    //---------------------------------------------------------------------
2565        void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
2566        {
2567        HRESULT hr;
2568
2569        // TODO: attempt to detect duplicates
2570        const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings();
2571        VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend;
2572        size_t source = 0;
2573        iend = binds.end();
2574        for (i = binds.begin(); i != iend; ++i, ++source)
2575        {
2576            // Unbind gap sources
2577            for ( ; source < i->first; ++source)
2578            {
2579                hr = mpD3DDevice->SetStreamSource(static_cast<UINT>(source), NULL, 0, 0);
2580                if (FAILED(hr))
2581                {
2582                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source", 
2583                        "D3D9RenderSystem::setVertexBufferBinding");
2584                }
2585            }
2586
2587            const D3D9HardwareVertexBuffer* d3d9buf = 
2588                static_cast<const D3D9HardwareVertexBuffer*>(i->second.get());
2589            hr = mpD3DDevice->SetStreamSource(
2590                static_cast<UINT>(source),
2591                d3d9buf->getD3D9VertexBuffer(),
2592                0, // no stream offset, this is handled in _render instead
2593                static_cast<UINT>(d3d9buf->getVertexSize()) // stride
2594                );
2595            if (FAILED(hr))
2596            {
2597                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source for buffer binding", 
2598                    "D3D9RenderSystem::setVertexBufferBinding");
2599            }
2600
2601
2602        }
2603
2604                // Unbind any unused sources
2605                for (size_t unused = source; unused < mLastVertexSourceCount; ++unused)
2606                {
2607                       
2608            hr = mpD3DDevice->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0);
2609            if (FAILED(hr))
2610            {
2611                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source", 
2612                    "D3D9RenderSystem::setVertexBufferBinding");
2613            }
2614                       
2615                }
2616                mLastVertexSourceCount = source;
2617               
2618        }
2619    //---------------------------------------------------------------------
2620    void D3D9RenderSystem::_render(const RenderOperation& op)
2621        {
2622        // Exit immediately if there is nothing to render
2623        // This caused a problem on FireGL 8800
2624        if (op.vertexData->vertexCount == 0)
2625            return;
2626
2627        // Call super class
2628                RenderSystem::_render(op);
2629
2630        // To think about: possibly remove setVertexDeclaration and
2631        // setVertexBufferBinding from RenderSystem since the sequence is
2632        // a bit too D3D9-specific?
2633                setVertexDeclaration(op.vertexData->vertexDeclaration);
2634        setVertexBufferBinding(op.vertexData->vertexBufferBinding);
2635
2636                // Determine rendering operation
2637                D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
2638                DWORD primCount = 0;
2639        switch( op.operationType )
2640                {
2641        case RenderOperation::OT_POINT_LIST:
2642                        primType = D3DPT_POINTLIST;
2643                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount);
2644                        break;
2645
2646                case RenderOperation::OT_LINE_LIST:
2647                        primType = D3DPT_LINELIST;
2648                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2;
2649                        break;
2650
2651                case RenderOperation::OT_LINE_STRIP:
2652                        primType = D3DPT_LINESTRIP;
2653                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1;
2654                        break;
2655
2656                case RenderOperation::OT_TRIANGLE_LIST:
2657                        primType = D3DPT_TRIANGLELIST;
2658                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3;
2659                        break;
2660
2661                case RenderOperation::OT_TRIANGLE_STRIP:
2662                        primType = D3DPT_TRIANGLESTRIP;
2663                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
2664                        break;
2665
2666                case RenderOperation::OT_TRIANGLE_FAN:
2667                        primType = D3DPT_TRIANGLEFAN;
2668                        primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
2669                        break;
2670                }
2671
2672        if (!primCount)
2673                        return;
2674
2675                // Issue the op
2676        HRESULT hr;
2677                if( op.useIndexes )
2678                {
2679            D3D9HardwareIndexBuffer* d3dIdxBuf = 
2680                static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get());
2681                        hr = mpD3DDevice->SetIndices( d3dIdxBuf->getD3DIndexBuffer() );
2682                        if (FAILED(hr))
2683            {
2684                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set index buffer", "D3D9RenderSystem::_render" );
2685            }
2686
2687            do
2688            {
2689                // do indexed draw operation
2690                            hr = mpD3DDevice->DrawIndexedPrimitive(
2691                    primType, 
2692                    static_cast<INT>(op.vertexData->vertexStart), 
2693                    0, // Min vertex index - assume we can go right down to 0
2694                    static_cast<UINT>(op.vertexData->vertexCount), 
2695                    static_cast<UINT>(op.indexData->indexStart), 
2696                    static_cast<UINT>(primCount)
2697                    );
2698
2699            } while (updatePassIterationRenderState());
2700                }
2701                else
2702        {
2703            // nfz: gpu_iterate
2704            do
2705            {
2706                // Unindexed, a little simpler!
2707                            hr = mpD3DDevice->DrawPrimitive(
2708                    primType, 
2709                    static_cast<UINT>(op.vertexData->vertexStart), 
2710                    static_cast<UINT>(primCount)
2711                    ); 
2712
2713            } while (updatePassIterationRenderState());
2714        } 
2715
2716                if( FAILED( hr ) )
2717                {
2718                        String msg = DXGetErrorDescription9(hr);
2719                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to DrawPrimitive : " + msg, "D3D9RenderSystem::_render" );
2720                }
2721       
2722        }
2723    //---------------------------------------------------------------------
2724    void D3D9RenderSystem::setNormaliseNormals(bool normalise)
2725    {
2726        __SetRenderState(D3DRS_NORMALIZENORMALS, 
2727            normalise ? TRUE : FALSE);
2728    }
2729        //---------------------------------------------------------------------
2730    void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg)
2731    {
2732        HRESULT hr;
2733        switch (prg->getType())
2734        {
2735        case GPT_VERTEX_PROGRAM:
2736            hr = mpD3DDevice->SetVertexShader(
2737                static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader());
2738            if (FAILED(hr))
2739            {
2740                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetVertexShader", "D3D9RenderSystem::bindGpuProgram");
2741            }
2742            break;
2743        case GPT_FRAGMENT_PROGRAM:
2744            hr = mpD3DDevice->SetPixelShader(
2745                static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader());
2746            if (FAILED(hr))
2747            {
2748                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetPixelShader", "D3D9RenderSystem::bindGpuProgram");
2749            }
2750            break;
2751        };
2752       
2753        RenderSystem::bindGpuProgram(prg);
2754
2755    }
2756        //---------------------------------------------------------------------
2757    void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
2758    {
2759        HRESULT hr;
2760        switch(gptype)
2761        {
2762        case GPT_VERTEX_PROGRAM:
2763            mActiveVertexGpuProgramParameters.setNull();
2764            hr = mpD3DDevice->SetVertexShader(NULL);
2765            if (FAILED(hr))
2766            {
2767                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetVertexShader to NULL", 
2768                    "D3D9RenderSystem::unbindGpuProgram");
2769            }
2770            break;
2771        case GPT_FRAGMENT_PROGRAM:
2772            mActiveFragmentGpuProgramParameters.setNull();
2773            hr = mpD3DDevice->SetPixelShader(NULL);
2774            if (FAILED(hr))
2775            {
2776                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetPixelShader to NULL", 
2777                    "D3D9RenderSystem::unbindGpuProgram");
2778            }
2779            break;
2780        };
2781        RenderSystem::unbindGpuProgram(gptype);
2782    }
2783        //---------------------------------------------------------------------
2784    void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 
2785        GpuProgramParametersSharedPtr params)
2786    {
2787        HRESULT hr;
2788                const GpuLogicalBufferStruct* floatLogical = params->getFloatLogicalBufferStruct();
2789                const GpuLogicalBufferStruct* intLogical = params->getIntLogicalBufferStruct();
2790
2791        switch(gptype)
2792        {
2793        case GPT_VERTEX_PROGRAM:
2794            mActiveVertexGpuProgramParameters = params;
2795                        {
2796                                OGRE_LOCK_MUTEX(floatLogical->mutex)
2797
2798                                for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
2799                                        i != floatLogical->map.end(); ++i)
2800                                {
2801                                        size_t logicalIndex = i->first;
2802                                        const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
2803                                        size_t slotCount = i->second.currentSize / 4;
2804                                        assert (i->second.currentSize % 4 == 0 && "Should not have any "
2805                                                "elements less than 4 wide for D3D9");
2806
2807                                        if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantF(
2808                                                logicalIndex, pFloat, slotCount)))
2809                                        {
2810                                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2811                                                        "Unable to upload vertex shader float parameters", 
2812                                                        "D3D9RenderSystem::bindGpuProgramParameters");
2813                                        }
2814
2815                                }
2816
2817                        }
2818                        // bind ints
2819                        {
2820                                OGRE_LOCK_MUTEX(intLogical->mutex)
2821
2822                                for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
2823                                        i != intLogical->map.end(); ++i)
2824                                {
2825                                        size_t logicalIndex = i->first;
2826                                        const int* pInt = params->getIntPointer(i->second.physicalIndex);
2827                                        size_t slotCount = i->second.currentSize / 4;
2828                                        assert (i->second.currentSize % 4 == 0 && "Should not have any "
2829                                                "elements less than 4 wide for D3D9");
2830
2831                                        if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantI(
2832                                                logicalIndex, pInt, slotCount)))
2833                                        {
2834                                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2835                                                        "Unable to upload vertex shader int parameters", 
2836                                                        "D3D9RenderSystem::bindGpuProgramParameters");
2837                                        }
2838
2839                                }
2840
2841                        }
2842
2843            break;
2844        case GPT_FRAGMENT_PROGRAM:
2845            mActiveFragmentGpuProgramParameters = params;
2846                        {
2847                                OGRE_LOCK_MUTEX(floatLogical->mutex)
2848
2849                                for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
2850                                        i != floatLogical->map.end(); ++i)
2851                                {
2852                                        size_t logicalIndex = i->first;
2853                                        const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
2854                                        size_t slotCount = i->second.currentSize / 4;
2855                                        assert (i->second.currentSize % 4 == 0 && "Should not have any "
2856                                                "elements less than 4 wide for D3D9");
2857
2858                                        if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantF(
2859                                                logicalIndex, pFloat, slotCount)))
2860                                        {
2861                                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2862                                                        "Unable to upload pixel shader float parameters", 
2863                                                        "D3D9RenderSystem::bindGpuProgramParameters");
2864                                        }
2865
2866                                }
2867
2868                        }
2869                        // bind ints
2870                        {
2871                                OGRE_LOCK_MUTEX(intLogical->mutex)
2872
2873                                for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
2874                                        i != intLogical->map.end(); ++i)
2875                                {
2876                                        size_t logicalIndex = i->first;
2877                                        const int* pInt = params->getIntPointer(i->second.physicalIndex);
2878                                        size_t slotCount = i->second.currentSize / 4;
2879                                        assert (i->second.currentSize % 4 == 0 && "Should not have any "
2880                                                "elements less than 4 wide for D3D9");
2881
2882                                        if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantI(
2883                                                logicalIndex, pInt, slotCount)))
2884                                        {
2885                                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2886                                                        "Unable to upload pixel shader int parameters", 
2887                                                        "D3D9RenderSystem::bindGpuProgramParameters");
2888                                        }
2889
2890                                }
2891
2892                        }
2893            break;
2894        };
2895    }
2896        //---------------------------------------------------------------------
2897    void D3D9RenderSystem::bindGpuProgramPassIterationParameters(GpuProgramType gptype)
2898    {
2899
2900        HRESULT hr;
2901                size_t physicalIndex = 0;
2902                size_t logicalIndex = 0;
2903                const float* pFloat;
2904
2905        switch(gptype)
2906        {
2907        case GPT_VERTEX_PROGRAM:
2908                        if (mActiveVertexGpuProgramParameters->hasPassIterationNumber())
2909                        {
2910                    physicalIndex = mActiveVertexGpuProgramParameters->getPassIterationNumberIndex();
2911                                logicalIndex = mActiveVertexGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex);
2912                                pFloat = mActiveVertexGpuProgramParameters->getFloatPointer(physicalIndex);
2913                               
2914                if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantF(
2915                        logicalIndex, pFloat, 1)))
2916                                {
2917                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2918                                                "Unable to upload vertex shader multi pass parameters", 
2919                                                "D3D9RenderSystem::bindGpuProgramMultiPassParameters");
2920                }
2921            }
2922            break;
2923
2924        case GPT_FRAGMENT_PROGRAM:
2925            if (mActiveFragmentGpuProgramParameters->hasPassIterationNumber())
2926            {
2927                                physicalIndex = mActiveFragmentGpuProgramParameters->getPassIterationNumberIndex();
2928                                logicalIndex = mActiveFragmentGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex);
2929                                pFloat = mActiveFragmentGpuProgramParameters->getFloatPointer(physicalIndex);
2930                if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantF(
2931                        logicalIndex, pFloat, 1)))
2932                {
2933                    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
2934                                                "Unable to upload pixel shader multi pass parameters", 
2935                                                "D3D9RenderSystem::bindGpuProgramMultiPassParameters");
2936                }
2937            }
2938            break;
2939
2940        }
2941    }
2942    //---------------------------------------------------------------------
2943    void D3D9RenderSystem::setClipPlanes(const PlaneList& clipPlanes)
2944    {
2945        size_t i;
2946        size_t numClipPlanes;
2947        float dx9ClipPlane[4];
2948        DWORD mask = 0;
2949        HRESULT hr;
2950
2951        numClipPlanes = clipPlanes.size();
2952        for (i = 0; i < numClipPlanes; ++i)
2953        {
2954            const Plane& plane = clipPlanes[i];
2955
2956            dx9ClipPlane[0] = plane.normal.x;
2957            dx9ClipPlane[1] = plane.normal.y;
2958            dx9ClipPlane[2] = plane.normal.z;
2959            dx9ClipPlane[3] = plane.d;
2960
2961            hr = mpD3DDevice->SetClipPlane(i, dx9ClipPlane);
2962            if (FAILED(hr))
2963            {
2964                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set clip plane", 
2965                    "D3D9RenderSystem::setClipPlanes");
2966            }
2967
2968            mask |= (1 << i);
2969        }
2970
2971        hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask);
2972        if (FAILED(hr))
2973        {
2974            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set render state for clip planes", 
2975                "D3D9RenderSystem::setClipPlanes");
2976        }
2977    }
2978        //---------------------------------------------------------------------
2979    void D3D9RenderSystem::setScissorTest(bool enabled, size_t left, size_t top, size_t right,
2980        size_t bottom)
2981    {
2982        HRESULT hr;
2983        if (enabled)
2984        {
2985            if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE)))
2986            {
2987                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable scissor rendering state; " + getErrorDescription(hr), 
2988                    "D3D9RenderSystem::setScissorTest");
2989            }
2990            RECT rect;
2991            rect.left = left;
2992            rect.top = top;
2993            rect.bottom = bottom;
2994            rect.right = right;
2995            if (FAILED(hr = mpD3DDevice->SetScissorRect(&rect)))
2996            {
2997                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set scissor rectangle; " + getErrorDescription(hr), 
2998                    "D3D9RenderSystem::setScissorTest");
2999            }
3000        }
3001        else
3002        {
3003            if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE)))
3004            {
3005                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable scissor rendering state; " + getErrorDescription(hr), 
3006                    "D3D9RenderSystem::setScissorTest");
3007            }
3008        }
3009    }
3010    //---------------------------------------------------------------------
3011    void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers, 
3012        const ColourValue& colour, Real depth, unsigned short stencil)
3013    {
3014        DWORD flags = 0;
3015        if (buffers & FBT_COLOUR)
3016        {
3017            flags |= D3DCLEAR_TARGET;
3018        }
3019        if (buffers & FBT_DEPTH)
3020        {
3021            flags |= D3DCLEAR_ZBUFFER;
3022        }
3023        // Only try to clear the stencil buffer if supported
3024        if (buffers & FBT_STENCIL && mCapabilities->hasCapability(RSC_HWSTENCIL))
3025        {
3026            flags |= D3DCLEAR_STENCIL;
3027        }
3028        HRESULT hr;
3029        if( FAILED( hr = mpD3DDevice->Clear( 
3030            0, 
3031            NULL, 
3032            flags,
3033            colour.getAsARGB(), 
3034            depth, 
3035            stencil ) ) )
3036        {
3037            String msg = DXGetErrorDescription9(hr);
3038            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error clearing frame buffer : " 
3039                + msg, "D3D9RenderSystem::clearFrameBuffer" );
3040        }
3041    }
3042    //---------------------------------------------------------------------
3043    void D3D9RenderSystem::_makeProjectionMatrix(Real left, Real right, 
3044        Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest,
3045        bool forGpuProgram)
3046    {
3047        // Correct position for off-axis projection matrix
3048        if (!forGpuProgram)
3049        {
3050            Real offsetX = left + right;
3051            Real offsetY = top + bottom;
3052
3053            left -= offsetX;
3054            right -= offsetX;
3055            top -= offsetY;
3056            bottom -= offsetY;
3057        }
3058
3059        Real width = right - left;
3060        Real height = top - bottom;
3061        Real q, qn;
3062        if (farPlane == 0)
3063        {
3064            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
3065            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
3066        }
3067        else
3068        {
3069            q = farPlane / ( farPlane - nearPlane );
3070            qn = -q * nearPlane;
3071        }
3072        dest = Matrix4::ZERO;
3073        dest[0][0] = 2 * nearPlane / width;
3074        dest[0][2] = (right+left) / width;
3075        dest[1][1] = 2 * nearPlane / height;
3076        dest[1][2] = (top+bottom) / height;
3077        if (forGpuProgram)
3078        {
3079            dest[2][2] = -q;
3080            dest[3][2] = -1.0f;
3081        }
3082        else
3083        {
3084            dest[2][2] = q;
3085            dest[3][2] = 1.0f;
3086        }
3087        dest[2][3] = qn;
3088    }
3089
3090    // ------------------------------------------------------------------
3091    void D3D9RenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D)
3092    {
3093        float plane[4] = { A, B, C, D };
3094        mpD3DDevice->SetClipPlane (index, plane);
3095    }
3096
3097    // ------------------------------------------------------------------
3098    void D3D9RenderSystem::enableClipPlane (ushort index, bool enable)
3099    {
3100        DWORD prev;
3101        mpD3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev);
3102        __SetRenderState(D3DRS_CLIPPLANEENABLE, enable?
3103                        (prev | (1 << index)) : (prev & ~(1 << index)));
3104    }
3105    //---------------------------------------------------------------------
3106    HardwareOcclusionQuery* D3D9RenderSystem::createHardwareOcclusionQuery(void)
3107    {
3108                D3D9HardwareOcclusionQuery* ret = new D3D9HardwareOcclusionQuery (mpD3DDevice); 
3109                mHwOcclusionQueries.push_back(ret);
3110                return ret;
3111    }
3112    //---------------------------------------------------------------------
3113    Real D3D9RenderSystem::getHorizontalTexelOffset(void)
3114    {
3115        // D3D considers the origin to be in the center of a pixel
3116        return -0.5f;
3117    }
3118    //---------------------------------------------------------------------
3119    Real D3D9RenderSystem::getVerticalTexelOffset(void)
3120    {
3121        // D3D considers the origin to be in the center of a pixel
3122        return -0.5f;
3123    }
3124    //---------------------------------------------------------------------
3125    void D3D9RenderSystem::_applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane, 
3126        bool forGpuProgram)
3127    {
3128        // Thanks to Eric Lenyel for posting this calculation at www.terathon.com
3129
3130        // Calculate the clip-space corner point opposite the clipping plane
3131        // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
3132        // transform it into camera space by multiplying it
3133        // by the inverse of the projection matrix
3134
3135        /* generalised version
3136        Vector4 q = matrix.inverse() *
3137            Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f);
3138        */
3139        Vector4 q;
3140        q.x = Math::Sign(plane.normal.x) / matrix[0][0];
3141        q.y = Math::Sign(plane.normal.y) / matrix[1][1];
3142        q.z = 1.0F; 
3143        // flip the next bit from Lengyel since we're right-handed
3144        if (forGpuProgram)
3145        {
3146            q.w = (1.0F - matrix[2][2]) / matrix[2][3];
3147        }
3148        else
3149        {
3150            q.w = (1.0F + matrix[2][2]) / matrix[2][3];
3151        }
3152
3153        // Calculate the scaled plane vector
3154        Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
3155        Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q)));
3156
3157        // Replace the third row of the projection matrix
3158        matrix[2][0] = c.x;
3159        matrix[2][1] = c.y;
3160        // flip the next bit from Lengyel since we're right-handed
3161        if (forGpuProgram)
3162        {
3163            matrix[2][2] = c.z; 
3164        }
3165        else
3166        {
3167            matrix[2][2] = -c.z; 
3168        }
3169        matrix[2][3] = c.w;       
3170    }
3171    //---------------------------------------------------------------------
3172    Real D3D9RenderSystem::getMinimumDepthInputValue(void)
3173    {
3174        // Range [0.0f, 1.0f]
3175        return 0.0f;
3176    }
3177    //---------------------------------------------------------------------
3178    Real D3D9RenderSystem::getMaximumDepthInputValue(void)
3179    {
3180        // Range [0.0f, 1.0f]
3181        // D3D inverts even identity view matrices, so maximum INPUT is -1.0
3182        return -1.0f;
3183    }
3184        //---------------------------------------------------------------------
3185        void D3D9RenderSystem::restoreLostDevice(void)
3186        {
3187                // Release all non-managed resources
3188
3189                // Cleanup depth stencils
3190                _cleanupDepthStencils();
3191
3192                // Set all texture units to nothing
3193                _disableTextureUnitsFrom(0);
3194
3195                // Unbind any vertex streams
3196                for (size_t i = 0; i < mLastVertexSourceCount; ++i)
3197                {
3198                        mpD3DDevice->SetStreamSource(i, NULL, 0, 0);
3199                }
3200        mLastVertexSourceCount = 0;
3201
3202        // Release all automatic temporary buffers and free unused
3203        // temporary buffers, so we doesn't need to recreate them,
3204        // and they will reallocate on demand. This save a lot of
3205        // release/recreate of non-managed vertex buffers which
3206        // wasn't need at all.
3207        mHardwareBufferManager->_releaseBufferCopies(true);
3208
3209                // We have to deal with non-managed textures and vertex buffers
3210                // GPU programs don't have to be restored
3211                static_cast<D3D9TextureManager*>(mTextureManager)->releaseDefaultPoolResources();
3212                static_cast<D3D9HardwareBufferManager*>(mHardwareBufferManager)
3213                        ->releaseDefaultPoolResources();
3214
3215                // release additional swap chains (secondary windows)
3216                SecondaryWindowList::iterator sw;
3217                for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
3218                {
3219                        (*sw)->destroyD3DResources();
3220                }
3221
3222                D3DPRESENT_PARAMETERS* presParams = mPrimaryWindow->getPresentationParameters();
3223                // Reset the device, using the primary window presentation params
3224                HRESULT hr = mpD3DDevice->Reset(presParams);
3225
3226                if (hr == D3DERR_DEVICELOST)
3227                {
3228                        // Don't continue
3229                        return;
3230                }
3231                else if (FAILED(hr))
3232                {
3233                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, 
3234                                "Cannot reset device! " + getErrorDescription(hr), 
3235                                "D3D9RenderWindow::restoreLostDevice" );
3236                }
3237
3238                StringUtil::StrStreamType str;
3239                str << "Reset device ok w:" << presParams->BackBufferWidth
3240                        << " h:" << presParams->BackBufferHeight;
3241                LogManager::getSingleton().logMessage(str.str());
3242                // If windowed, we have to reset the size here
3243                // since a fullscreen switch may have occurred
3244                if (mPrimaryWindow->_getSwitchingFullscreen())
3245                {
3246                        mPrimaryWindow->_finishSwitchingFullscreen();
3247                }
3248
3249
3250                // will have lost basic states
3251                mBasicStatesInitialised = false;
3252        mVertexProgramBound = false;
3253        mFragmentProgramBound = false;
3254
3255
3256                // recreate additional swap chains
3257                for (sw = mSecondaryWindows.begin(); sw != mSecondaryWindows.end(); ++sw)
3258                {
3259                        (*sw)->createD3DResources();
3260                }
3261
3262                // Recreate all non-managed resources
3263                static_cast<D3D9TextureManager*>(mTextureManager)
3264                        ->recreateDefaultPoolResources();
3265                static_cast<D3D9HardwareBufferManager*>(mHardwareBufferManager)
3266                        ->recreateDefaultPoolResources();
3267                       
3268                LogManager::getSingleton().logMessage("!!! Direct3D Device successfully restored.");
3269
3270                mDeviceLost = false;
3271
3272                fireEvent("DeviceRestored");
3273
3274        }
3275        //---------------------------------------------------------------------
3276        bool D3D9RenderSystem::isDeviceLost(void)
3277        {
3278                return mDeviceLost;
3279        }
3280        //---------------------------------------------------------------------
3281        void D3D9RenderSystem::_notifyDeviceLost(void)
3282        {
3283                LogManager::getSingleton().logMessage("!!! Direct3D Device Lost!");
3284                mDeviceLost = true;
3285                // will have lost basic states
3286                mBasicStatesInitialised = false;
3287
3288                fireEvent("DeviceLost");
3289        }
3290
3291        //---------------------------------------------------------------------
3292        // Formats to try, in decreasing order of preference
3293        D3DFORMAT ddDepthStencilFormats[]={
3294                D3DFMT_D24FS8,
3295                D3DFMT_D24S8,
3296                D3DFMT_D24X4S4,
3297                D3DFMT_D24X8,
3298                D3DFMT_D15S1,
3299                D3DFMT_D16,
3300                D3DFMT_D32
3301        };
3302#define NDSFORMATS (sizeof(ddDepthStencilFormats)/sizeof(D3DFORMAT))
3303       
3304        D3DFORMAT D3D9RenderSystem::_getDepthStencilFormatFor(D3DFORMAT fmt)
3305        {
3306                /// Check if result is cached
3307                DepthStencilHash::iterator i = mDepthStencilHash.find((unsigned int)fmt);
3308                if(i != mDepthStencilHash.end())
3309                        return i->second;
3310                /// If not, probe with CheckDepthStencilMatch
3311                D3DFORMAT dsfmt = D3DFMT_UNKNOWN;
3312
3313                /// Get description of primary render target
3314                LPDIRECT3DSURFACE9 mSurface = mPrimaryWindow->getRenderSurface();
3315                D3DSURFACE_DESC srfDesc;
3316
3317                if(!FAILED(mSurface->GetDesc(&srfDesc)))
3318                {
3319                        /// Probe all depth stencil formats
3320                        /// Break on first one that matches
3321                        for(size_t x=0; x<NDSFORMATS; ++x)
3322                        {
3323                // Verify that the depth format exists
3324                if (mpD3D->CheckDeviceFormat(
3325                    mActiveD3DDriver->getAdapterNumber(),
3326                    D3DDEVTYPE_HAL,
3327                    srfDesc.Format,
3328                    D3DUSAGE_DEPTHSTENCIL,
3329                    D3DRTYPE_SURFACE,
3330                    ddDepthStencilFormats[x]) != D3D_OK)
3331                {
3332                    continue;
3333                }
3334                // Verify that the depth format is compatible
3335                                if(mpD3D->CheckDepthStencilMatch(
3336                                        mActiveD3DDriver->getAdapterNumber(),
3337                                        D3DDEVTYPE_HAL, srfDesc.Format,
3338                                        fmt, ddDepthStencilFormats[x]) == D3D_OK)
3339                                {
3340                                        dsfmt = ddDepthStencilFormats[x];
3341                                        break;
3342                                }
3343                        }
3344                }
3345                /// Cache result
3346                mDepthStencilHash[(unsigned int)fmt] = dsfmt;
3347                return dsfmt;
3348        }
3349        IDirect3DSurface9* D3D9RenderSystem::_getDepthStencilFor(D3DFORMAT fmt, D3DMULTISAMPLE_TYPE multisample, size_t width, size_t height)
3350        {
3351                D3DFORMAT dsfmt = _getDepthStencilFormatFor(fmt);
3352                if(dsfmt == D3DFMT_UNKNOWN)
3353                        return 0;
3354                IDirect3DSurface9 *surface = 0;
3355
3356                /// Check if result is cached
3357                ZBufferFormat zbfmt(dsfmt, multisample);
3358                ZBufferHash::iterator i = mZBufferHash.find(zbfmt);
3359                if(i != mZBufferHash.end())
3360                {
3361                        /// Check if size is larger or equal
3362                        if(i->second.width >= width && i->second.height >= height)
3363                        {
3364                                surface = i->second.surface;
3365                        } 
3366                        else
3367                        {
3368                                /// If not, destroy current buffer
3369                                i->second.surface->Release();
3370                                mZBufferHash.erase(i);
3371                        }
3372                }
3373                if(!surface)
3374                {
3375                        /// If not, create the depthstencil surface
3376                        HRESULT hr = mpD3DDevice->CreateDepthStencilSurface( 
3377                                width, 
3378                                height, 
3379                                dsfmt, 
3380                                multisample, 
3381                                NULL, 
3382                                TRUE,  // discard true or false?
3383                                &surface, 
3384                                NULL);
3385                        if(FAILED(hr))
3386                        {
3387                                String msg = DXGetErrorDescription9(hr);
3388                                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error CreateDepthStencilSurface : " + msg, "D3D9RenderSystem::_getDepthStencilFor" );
3389                        }
3390                        /// And cache it
3391                        ZBufferRef zb;
3392                        zb.surface = surface;
3393                        zb.width = width;
3394                        zb.height = height;
3395                        mZBufferHash[zbfmt] = zb;
3396                }
3397                return surface;
3398        }
3399        void D3D9RenderSystem::_cleanupDepthStencils()
3400        {
3401                for(ZBufferHash::iterator i = mZBufferHash.begin(); i != mZBufferHash.end(); ++i)
3402                {
3403                        /// Release buffer
3404                        i->second.surface->Release();
3405                }
3406                mZBufferHash.clear();
3407        }
3408        void D3D9RenderSystem::registerThread()
3409        {
3410                // nothing to do - D3D9 shares rendering context already
3411        }
3412        void D3D9RenderSystem::unregisterThread()
3413        {
3414                // nothing to do - D3D9 shares rendering context already
3415        }
3416        void D3D9RenderSystem::preExtraThreadsStarted()
3417        {
3418                // nothing to do - D3D9 shares rendering context already
3419        }
3420        void D3D9RenderSystem::postExtraThreadsStarted()
3421        {
3422                // nothing to do - D3D9 shares rendering context already
3423        }
3424
3425}
Note: See TracBrowser for help on using the repository browser.