source: OGRE/trunk/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9RenderSystem.cpp @ 657

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

added ogre dependencies and patched ogre sources

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