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

Revision 692, 108.5 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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