source: OGRE/trunk/ogre_changes/Ogre1.2/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp @ 768

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