Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreD3D9RenderSystem.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreD3D9RenderSystem.h"
00026 #include "OgreD3D9Prerequisites.h"
00027 #include "OgreD3D9DriverList.h"
00028 #include "OgreD3D9Driver.h"
00029 #include "OgreD3D9VideoModeList.h"
00030 #include "OgreD3D9VideoMode.h"
00031 #include "OgreD3D9RenderWindow.h"
00032 #include "OgreD3D9TextureManager.h"
00033 #include "OgreD3D9Texture.h"
00034 #include "OgreLogManager.h"
00035 #include "OgreLight.h"
00036 #include "OgreMath.h"
00037 #include "OgreD3D9HardwareBufferManager.h"
00038 #include "OgreD3D9HardwareIndexBuffer.h"
00039 #include "OgreD3D9HardwareVertexBuffer.h"
00040 #include "OgreD3D9VertexDeclaration.h"
00041 #include "OgreD3D9GpuProgram.h"
00042 #include "OgreD3D9GpuProgramManager.h"
00043 //#include "OgreD3D9HLSLProgramFactory.h"
00044 #include "OgreHighLevelGpuProgramManager.h"
00045 #include "OgreD3D9HardwareOcclusionQuery.h"
00046 #include "OgreFrustum.h"
00047 
00048 
00049 
00050 namespace Ogre 
00051 {
00052 
00053     const Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE(
00054         0.5,    0,  0, -0.5, 
00055         0, -0.5,  0, -0.5, 
00056         0,    0,  0,   1,
00057         0,    0,  0,   1);
00058 
00059     const Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_ORTHO(
00060         -0.5,    0,  0, -0.5, 
00061         0, 0.5,  0, -0.5, 
00062         0,    0,  0,   1,
00063         0,    0,  0,   1);
00064 
00065     //---------------------------------------------------------------------
00066     D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance )
00067     {
00068         OgreGuard( "D3D9RenderSystem::D3D9RenderSystem" );
00069         LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " created." );
00070 
00071         // set the instance being passed 
00072         mhInstance = hInstance;
00073 
00074         // set pointers to NULL
00075         mpD3D = NULL;
00076         mpD3DDevice = NULL;
00077         mDriverList = NULL;
00078         mActiveD3DDriver = NULL;
00079         mExternalHandle = NULL;
00080         mTextureManager = NULL;
00081         mHardwareBufferManager = NULL;
00082         mGpuProgramManager = NULL;
00083         //mHLSLProgramFactory = NULL;
00084 
00085         // init lights
00086         for(int i = 0; i < MAX_LIGHTS; i++ )
00087             mLights[i] = 0;
00088 
00089         // Create our Direct3D object
00090         if( NULL == (mpD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
00091             Except( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" );
00092 
00093         // set config options defaults
00094         initConfigOptions();
00095 
00096         // fsaa options
00097         mFSAAType = D3DMULTISAMPLE_NONE;
00098         mFSAAQuality = 0;
00099 
00100         // set stages desc. to defaults
00101         for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++)
00102         {
00103             mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
00104             mTexStageDesc[n].coordIndex = 0;
00105             mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
00106             mTexStageDesc[n].pTex = 0;
00107         }
00108 
00109         mLastVertexSourceCount = 0;
00110 
00111         mCurrentLights = 0;
00112 
00113 
00114         OgreUnguard();
00115     }
00116     //---------------------------------------------------------------------
00117     D3D9RenderSystem::~D3D9RenderSystem()
00118     {
00119         OgreGuard( "D3D9RenderSystem::~D3D9RenderSystem" );
00120         shutdown();
00121 
00122         // Unbind any vertex streams to avoid memory leaks
00123         for (unsigned int i = 0; i < mLastVertexSourceCount; ++i)
00124         {
00125             HRESULT hr = mpD3DDevice->SetStreamSource(i, NULL, 0, 0);
00126         }
00127         
00128         
00129         SAFE_DELETE( mDriverList );
00130         SAFE_DELETE( mTextureManager );
00131         SAFE_DELETE(mHardwareBufferManager);
00132         //SAFE_DELETE(mHLSLProgramFactory);
00133         SAFE_DELETE(mGpuProgramManager);
00134         SAFE_RELEASE( mpD3D );
00135 
00136         if (mCapabilities)
00137         {
00138             delete mCapabilities;
00139             mCapabilities = NULL;
00140         }
00141 
00142         LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " destroyed." );
00143         OgreUnguard();
00144     }
00145     //---------------------------------------------------------------------
00146     const String& D3D9RenderSystem::getName() const
00147     {
00148         static String strName( "Direct3D9 Rendering SubSystem");
00149         return strName;
00150     }
00151     //---------------------------------------------------------------------
00152     D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers()
00153     {
00154         if( !mDriverList )
00155             mDriverList = new D3D9DriverList( mpD3D );
00156 
00157         return mDriverList;
00158     }
00159     //---------------------------------------------------------------------
00160     bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
00161     {
00162         HRESULT hr;
00163         hr = mpD3D->CheckDeviceMultiSampleType( 
00164                 adapterNum, 
00165                 deviceType, 
00166                 format, 
00167                 fullScreen, 
00168                 type, 
00169                 outQuality);
00170 
00171         if (SUCCEEDED(hr))
00172             return true;
00173         else
00174             return false;
00175     }
00176     //---------------------------------------------------------------------
00177     D3D9RenderSystem::initConfigOptions()
00178     {
00179         OgreGuard( "D3D9RenderSystem::initConfigOptions" );
00180 
00181         D3D9DriverList* driverList;
00182         D3D9Driver* driver;
00183 
00184         ConfigOption optDevice;
00185         ConfigOption optVideoMode;
00186         ConfigOption optFullScreen;
00187         ConfigOption optVSync;
00188         ConfigOption optAA;
00189 
00190         driverList = this->getDirect3DDrivers();
00191 
00192         optDevice.name = "Rendering Device";
00193         optDevice.currentValue = "";
00194         optDevice.possibleValues.clear();
00195         optDevice.immutable = false;
00196 
00197         optVideoMode.name = "Video Mode";
00198         optVideoMode.currentValue = "800 x 600 @ 32-bit colour";
00199         optVideoMode.immutable = false;
00200 
00201         optFullScreen.name = "Full Screen";
00202         optFullScreen.possibleValues.push_back( "Yes" );
00203         optFullScreen.possibleValues.push_back( "No" );
00204         optFullScreen.currentValue = "Yes";
00205         optFullScreen.immutable = false;
00206 
00207         for( unsigned j=0; j < driverList->count(); j++ )
00208         {
00209             driver = driverList->item(j);
00210             optDevice.possibleValues.push_back( driver->DriverDescription() );
00211             // Make first one default
00212             if( j==0 )
00213                 optDevice.currentValue = driver->DriverDescription();
00214         }
00215 
00216         optVSync.name = "VSync";
00217         optVSync.immutable = false;
00218         optVSync.possibleValues.push_back( "Yes" );
00219         optVSync.possibleValues.push_back( "No" );
00220         optVSync.currentValue = "No";
00221 
00222         optAA.name = "Anti aliasing";
00223         optAA.immutable = false;
00224         optAA.possibleValues.push_back( "None" );
00225         optAA.currentValue = "None";
00226 
00227         mOptions[optDevice.name] = optDevice;
00228         mOptions[optVideoMode.name] = optVideoMode;
00229         mOptions[optFullScreen.name] = optFullScreen;
00230         mOptions[optVSync.name] = optVSync;
00231         mOptions[optAA.name] = optAA;
00232 
00233         refreshD3DSettings();
00234 
00235         OgreUnguard();
00236     }
00237     //---------------------------------------------------------------------
00238     void D3D9RenderSystem::refreshD3DSettings()
00239     {
00240         OgreGuard( "D3D9RenderSystem::refreshD3DSettings" );
00241 
00242         ConfigOption* optVideoMode;
00243         D3D9Driver* driver;
00244         D3D9VideoMode* videoMode;
00245 
00246         ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
00247         if( opt != mOptions.end() )
00248         {
00249             for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
00250             {
00251                 driver = getDirect3DDrivers()->item(j);
00252                 if( driver->DriverDescription() == opt->second.currentValue )
00253                     break;
00254             }
00255 
00256             opt = mOptions.find( "Video Mode" );
00257             optVideoMode = &opt->second;
00258             optVideoMode->possibleValues.clear();
00259             // get vide modes for this device
00260             for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ )
00261             {
00262                 videoMode = driver->getVideoModeList()->item( k );
00263                 optVideoMode->possibleValues.push_back( videoMode->getDescription() );
00264             }
00265         }
00266 
00267         OgreUnguard();
00268     }
00269     //---------------------------------------------------------------------
00270     void D3D9RenderSystem::setConfigOption( const String &name, const String &value )
00271     {
00272         OgreGuard( "D3D9RenderSystem::setConfigOption" );
00273 
00274         char msg[128];
00275         sprintf( msg, "D3D9 : RenderSystem Option: %s = %s", name.c_str(), value.c_str() );
00276         LogManager::getSingleton().logMessage( msg );
00277 
00278         // Find option
00279         ConfigOptionMap::iterator it = mOptions.find( name );
00280 
00281         // Update
00282         if( it != mOptions.end() )
00283             it->second.currentValue = value;
00284         else
00285         {
00286             sprintf( msg, "Option named '%s' does not exist.", name.c_str() );
00287             Except( Exception::ERR_INVALIDPARAMS, msg, "D3D9RenderSystem::setConfigOption" );
00288         }
00289 
00290         // Refresh other options if D3DDriver changed
00291         if( name == "Rendering Device" )
00292             refreshD3DSettings();
00293 
00294         if( name == "Full Screen" )
00295         {
00296             // Video mode is applicable
00297             it = mOptions.find( "Video Mode" );
00298             if (it->second.currentValue == "")
00299                 it->second.currentValue = "800 x 600 @ 32-bit colour";
00300         }
00301 
00302         if( name == "Anti aliasing" )
00303         {
00304             if (value == "None")
00305                 _setFSAA(D3DMULTISAMPLE_NONE, 0);
00306             else 
00307             {
00308                 D3DMULTISAMPLE_TYPE fsaa = D3DMULTISAMPLE_NONE;
00309                 DWORD level = 0;
00310 
00311                 if (value.find_first_of("NonMaskable") != -1)
00312                 {
00313                     fsaa = D3DMULTISAMPLE_NONMASKABLE;
00314                     size_t pos = value.find_last_of(" ");
00315                     String sNum = value.substr(pos + 1);
00316                     level = StringConverter::parseInt(sNum);
00317                     level -= 1;
00318                 }
00319                 else if (value.find_first_of("Level") != -1)
00320                 {
00321                     size_t pos = value.find_last_of(" ");
00322                     String sNum = value.substr(pos + 1);
00323                     fsaa = (D3DMULTISAMPLE_TYPE)StringConverter::parseInt(sNum);
00324                 }
00325 
00326                 _setFSAA(fsaa, level);
00327             }
00328         }
00329 
00330         if( name == "VSync" )
00331         {
00332             if (value == "Yes")
00333                 mVSync = true;
00334             else
00335                 mVSync = false;
00336         }
00337 
00338         if( name == "Video Mode" )
00339         {
00340             ConfigOption* optFSAA;
00341             it = mOptions.find( "Anti aliasing" );
00342             optFSAA = &it->second;
00343             optFSAA->possibleValues.clear();
00344             optFSAA->possibleValues.push_back("None");
00345 
00346             it = mOptions.find("Rendering Device");
00347             D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue);
00348             if (driver)
00349             {
00350                 it = mOptions.find("Video Mode");
00351                 D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue);
00352                 if (videoMode)
00353                 {
00354                     // get non maskable FSAA for this VMODE
00355                     DWORD numLevels = 0;
00356                     bool bOK = this->_checkMultiSampleQuality(
00357                         D3DMULTISAMPLE_NONMASKABLE, 
00358                         &numLevels, 
00359                         videoMode->getFormat(), 
00360                         driver->getAdapterNumber(),
00361                         D3DDEVTYPE_HAL,
00362                         TRUE);
00363                     if (bOK && numLevels > 0)
00364                     {
00365                         for (DWORD n = 0; n < numLevels; n++)
00366                             optFSAA->possibleValues.push_back("NonMaskable " + StringConverter::toString(n + 1));
00367                     }
00368 
00369                     // set maskable levels supported
00370                     for (unsigned int n = 2; n < 17; n++)
00371                     {
00372                         bOK = this->_checkMultiSampleQuality(
00373                             (D3DMULTISAMPLE_TYPE)n, 
00374                             &numLevels, 
00375                             videoMode->getFormat(), 
00376                             driver->getAdapterNumber(),
00377                             D3DDEVTYPE_HAL,
00378                             TRUE);
00379                         if (bOK)
00380                             optFSAA->possibleValues.push_back("Level " + StringConverter::toString(n));
00381                     }
00382                 }
00383             }
00384         }
00385 
00386         OgreUnguard();
00387     }
00388     //---------------------------------------------------------------------
00389     String D3D9RenderSystem::validateConfigOptions()
00390     {
00391         ConfigOptionMap::iterator it;
00392         
00393         // check if video mode is selected
00394         it = mOptions.find( "Video Mode" );
00395         if( it->second.currentValue == "" )
00396             return "A video mode must be selected.";
00397 
00398         it = mOptions.find( "Rendering Device" );
00399         bool foundDriver = false;
00400         D3D9DriverList* driverList = getDirect3DDrivers();
00401         for( ushort j=0; j < driverList->count(); j++ )
00402         {
00403             if( driverList->item(j)->DriverDescription() == it->second.currentValue )
00404             {
00405                 foundDriver = true;
00406                 break;
00407             }
00408         }
00409 
00410         if (!foundDriver)
00411         {
00412             // Just pick the first driver
00413             setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
00414             return "Your DirectX driver name has changed since the last time you ran OGRE; "
00415                 "the 'Rendering Device' has been changed.";
00416         }
00417 
00418         it = mOptions.find( "VSync" );
00419         if( it->second.currentValue == "Yes" )
00420             mVSync = true;
00421         else
00422             mVSync = false;
00423 
00424         return "";
00425     }
00426     //---------------------------------------------------------------------
00427     ConfigOptionMap& D3D9RenderSystem::getConfigOptions()
00428     {
00429         // return a COPY of the current config options
00430         return mOptions;
00431     }
00432     //---------------------------------------------------------------------
00433     RenderWindow* D3D9RenderSystem::initialise( bool autoCreateWindow, const String& windowTitle )
00434     {
00435         RenderWindow* autoWindow = NULL;
00436         LogManager::getSingleton().logMessage( "D3D9 : Subsystem Initialising" );
00437 
00438         // Init using current settings
00439         mActiveD3DDriver = NULL;
00440         ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
00441         for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
00442         {
00443             if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
00444             {
00445                 mActiveD3DDriver = getDirect3DDrivers()->item(j);
00446                 break;
00447             }
00448         }
00449 
00450         if( !mActiveD3DDriver )
00451             Except( Exception::ERR_INVALIDPARAMS, "Problems finding requested Direct3D driver!", "D3D9RenderSystem::initialise" );
00452 
00453         if( autoCreateWindow )
00454         {
00455             bool fullScreen;
00456             opt = mOptions.find( "Full Screen" );
00457             if( opt == mOptions.end() )
00458                 Exception( Exception::ERR_INTERNAL_ERROR, "Can't find full screen option!", "D3D9RenderSystem::initialise" );
00459             fullScreen = opt->second.currentValue == "Yes";
00460 
00461             D3D9VideoMode* videoMode = NULL;
00462             unsigned int width, height, colourDepth;
00463             String temp;
00464 
00465             opt = mOptions.find( "Video Mode" );
00466             if( opt == mOptions.end() )
00467                 Exception( Exception::ERR_INTERNAL_ERROR, "Can't find Video Mode option!", "D3D9RenderSystem::initialise" );
00468 
00469             for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ )
00470             {
00471                 temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription();
00472                 if( temp == opt->second.currentValue )
00473                 {
00474                     videoMode = mActiveD3DDriver->getVideoModeList()->item(j);
00475                     break;
00476                 }
00477             }
00478 
00479             if( !videoMode )
00480                 Except( Exception::ERR_INTERNAL_ERROR, "Can't find requested video mode.", "D3D9RenderSystem::initialise" );
00481 
00482             width = videoMode->getWidth();
00483             height = videoMode->getHeight();
00484             colourDepth = videoMode->getColourDepth();
00485 
00486             autoWindow = this->createRenderWindow( windowTitle, width, height, colourDepth, fullScreen );
00487 
00488             // If we have 16bit depth buffer enable w-buffering.
00489             assert( autoWindow );
00490             if ( autoWindow->getColourDepth() == 16 ) 
00491             { 
00492                 mWBuffer = true;
00493             } 
00494             else 
00495             {
00496                 mWBuffer = false;
00497             }
00498         }
00499 
00500         LogManager::getSingleton().logMessage("***************************************");
00501 
00502         LogManager::getSingleton().logMessage("*** D3D9 : Subsystem Initialised OK ***");
00503         LogManager::getSingleton().logMessage("***************************************");
00504 
00505         // call superclass method
00506         RenderSystem::initialise( autoCreateWindow );
00507 
00508 
00509         return autoWindow;
00510     }
00511     //---------------------------------------------------------------------
00512     void D3D9RenderSystem::_setFSAA(D3DMULTISAMPLE_TYPE type, DWORD qualityLevel)
00513     {
00514         if (!mpD3DDevice)
00515         {
00516             mFSAAType = type;
00517             mFSAAQuality = qualityLevel;
00518         }
00519     }
00520     //---------------------------------------------------------------------
00521     void D3D9RenderSystem::reinitialise()
00522     {
00523         LogManager::getSingleton().logMessage( "D3D9 : Reinitialising" );
00524         this->shutdown();
00525         this->initialise( true );
00526     }
00527     //---------------------------------------------------------------------
00528     void D3D9RenderSystem::shutdown()
00529     {
00530         RenderSystem::shutdown();
00531         SAFE_DELETE( mDriverList );
00532         mActiveD3DDriver = NULL;
00533         LogManager::getSingleton().logMessage("D3D9 : Shutting down cleanly.");
00534     }
00535     //---------------------------------------------------------------------
00536     RenderWindow* D3D9RenderSystem::createRenderWindow( const String &name, unsigned int width, unsigned int height, unsigned int colourDepth,
00537         bool fullScreen, int left, int top, bool depthBuffer, RenderWindow* parentWindowHandle)
00538     {
00539         static bool firstWindow = true;
00540         
00541         OgreGuard( "D3D9RenderSystem::createRenderWindow" );
00542 
00543         String msg;
00544 
00545         // Make sure we don't already have a render target of the 
00546         // sam name as the one supplied
00547         if( mRenderTargets.find( name ) != mRenderTargets.end() )
00548         {
00549             msg = "A render target of the same name '" + name + "' already "
00550                 "exists.  You cannot create a new window with this name.";
00551             Except( Exception::ERR_INTERNAL_ERROR, msg, "D3D9RenderSystem::createRenderWindow" );
00552         }
00553 
00554         RenderWindow* win = new D3D9RenderWindow();
00555         if (!fullScreen && mExternalHandle)
00556         {
00557             D3D9RenderWindow *pWin32Window = (D3D9RenderWindow *)win;
00558             pWin32Window->SetExternalWindowHandle(mExternalHandle);
00559         }
00560 
00561         win->create( name, width, height, colourDepth, fullScreen, 
00562                 left, top, depthBuffer, &mhInstance, mActiveD3DDriver, 
00563                 parentWindowHandle, mFSAAType, mFSAAQuality, mVSync );
00564 
00565         attachRenderTarget( *win );
00566 
00567         // If this is the first window, get the D3D device and create the texture manager
00568         if( firstWindow )
00569         {
00570             win->getCustomAttribute( "D3DDEVICE", &mpD3DDevice );
00571 
00572             // Create the texture manager for use by others
00573             mTextureManager = new D3D9TextureManager( mpD3DDevice );
00574             // Also create hardware buffer manager
00575             mHardwareBufferManager = new D3D9HardwareBufferManager(mpD3DDevice);
00576 
00577             // Create the GPU program manager
00578             mGpuProgramManager = new D3D9GpuProgramManager(mpD3DDevice);
00579             // create & register HLSL factory
00580             //mHLSLProgramFactory = new D3D9HLSLProgramFactory();
00581             //HighLevelGpuProgramManager::getSingleton().addFactory(mHLSLProgramFactory);
00582             mGpuProgramManager->_pushSyntaxCode("hlsl");
00583 
00584 
00585             // Initialise the capabilities structures
00586             initCapabilities();
00587 
00588 
00589             firstWindow = false;
00590             
00591         }
00592 
00593         OgreUnguardRet( win );
00594     }
00595     //---------------------------------------------------------------------
00596     void D3D9RenderSystem::initCapabilities(void)
00597     {
00598         // get caps
00599         mpD3DDevice->GetDeviceCaps( &mCaps );
00600 
00601         // Check for hardware stencil support
00602         LPDIRECT3DSURFACE9 pSurf;
00603         D3DSURFACE_DESC surfDesc;
00604         mpD3DDevice->GetDepthStencilSurface(&pSurf);
00605         pSurf->GetDesc(&surfDesc);
00606         pSurf->Release();
00607 
00608         if (surfDesc.Format == D3DFMT_D24S8 || surfDesc.Format == D3DFMT_D24X8)
00609         {
00610             mCapabilities->setCapability(RSC_HWSTENCIL);
00611             // Actually, it's always 8-bit
00612             mCapabilities->setStencilBufferBitDepth(8);
00613 
00614         }
00615 
00616         // Set number of texture units
00617         mCapabilities->setNumTextureUnits(mCaps.MaxSimultaneousTextures);
00618         // Anisotropy?
00619         if (mCaps.MaxAnisotropy > 1)
00620             mCapabilities->setCapability(RSC_ANISOTROPY);
00621         // Automatic mipmap generation?
00622         if (mCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP)
00623             mCapabilities->setCapability(RSC_AUTOMIPMAP);
00624         // Blending between stages supported
00625         mCapabilities->setCapability(RSC_BLENDING);
00626         // Dot 3
00627         if (mCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3)
00628             mCapabilities->setCapability(RSC_DOT3);
00629         // Cube map
00630         if (mCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP)
00631             mCapabilities->setCapability(RSC_CUBEMAPPING);
00632 
00633         // We always support compression, D3DX will decompress if device does not support
00634         mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION);
00635         mCapabilities->setCapability(RSC_TEXTURE_COMPRESSION_DXT);
00636 
00637         // We always support VBOs
00638         mCapabilities->setCapability(RSC_VBO);
00639 
00640         // Scissor test
00641         if (mCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST)
00642             mCapabilities->setCapability(RSC_SCISSOR_TEST);
00643 
00644         // Two-sided stencil
00645         if (mCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED)
00646             mCapabilities->setCapability(RSC_TWO_SIDED_STENCIL);
00647 
00648         // stencil wrap
00649         if ((mCaps.StencilCaps & D3DSTENCILCAPS_INCR) && 
00650             (mCaps.StencilCaps & D3DSTENCILCAPS_DECR))
00651             mCapabilities->setCapability(RSC_STENCIL_WRAP);
00652 
00653         // Check for hardware occlusion support
00654         if ( ( mpD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION,  NULL ) ) == D3D_OK )   
00655         {
00656             mCapabilities->setCapability(RSC_HWOCCLUSION);
00657         }
00658         convertVertexShaderCaps();
00659         convertPixelShaderCaps();
00660 
00661         // User clip planes
00662         if (mCaps.MaxUserClipPlanes > 0)
00663         {
00664             mCapabilities->setCapability(RSC_USER_CLIP_PLANES);
00665         }
00666 
00667         // UBYTE4 type?
00668         if (mCaps.DeclTypes & D3DDTCAPS_UBYTE4)
00669         {
00670             mCapabilities->setCapability(RSC_VERTEX_FORMAT_UBYTE4);
00671         }
00672 
00673         // Infinite projection?
00674         // We have no capability for this, so we have to base this on our
00675         // experience and reports from users
00676         // Non-vertex program capable hardware does not appear to support it
00677         if (mCapabilities->hasCapability(RSC_VERTEX_PROGRAM))
00678         {
00679             // GeForce4 Ti (and presumably GeForce3) does not
00680             // render infinite projection properly, even though it does in GL
00681             // So exclude all cards prior to the FX range from doing infinite
00682             D3DADAPTER_IDENTIFIER9 adapterID = mActiveD3DDriver->getAdapterIdentifier();
00683             if (adapterID.VendorId != 0x10DE || // not nVidia
00684                 adapterID.DeviceId >= 0x0301) // or GeForce FX or above
00685             {
00686                 mCapabilities->setCapability(RSC_INFINITE_FAR_PLANE);
00687             }
00688             
00689         }
00690                 
00691 
00692         mCapabilities->log(LogManager::getSingleton().getDefaultLog());
00693     }
00694     //---------------------------------------------------------------------
00695     void D3D9RenderSystem::convertVertexShaderCaps(void)
00696     {
00697         ushort major, minor;
00698         major = static_cast<ushort>((mCaps.VertexShaderVersion & 0x0000FF00) >> 8);
00699         minor = static_cast<ushort>(mCaps.VertexShaderVersion & 0x000000FF);
00700 
00701         // Populate max version & params
00702         switch (major)
00703         {
00704         case 1:
00705             mCapabilities->setMaxVertexProgramVersion("vs_1_1");
00706             // No boolean params allowed
00707             mCapabilities->setVertexProgramConstantBoolCount(0);
00708             // No integer params allowed
00709             mCapabilities->setVertexProgramConstantIntCount(0);
00710             // float params, always 4D
00711             mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
00712            
00713             break;
00714         case 2:
00715             if (minor > 0)
00716             {
00717                 mCapabilities->setMaxVertexProgramVersion("vs_2_x");
00718             }
00719             else
00720             {
00721                 mCapabilities->setMaxVertexProgramVersion("vs_2_0");
00722             }
00723             // 16 boolean params allowed
00724             mCapabilities->setVertexProgramConstantBoolCount(16);
00725             // 16 integer params allowed, 4D
00726             mCapabilities->setVertexProgramConstantIntCount(16);
00727             // float params, always 4D
00728             mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
00729             break;
00730         case 3:
00731             mCapabilities->setMaxVertexProgramVersion("vs_3_0");
00732             // 16 boolean params allowed
00733             mCapabilities->setVertexProgramConstantBoolCount(16);
00734             // 16 integer params allowed, 4D
00735             mCapabilities->setVertexProgramConstantIntCount(16);
00736             // float params, always 4D
00737             mCapabilities->setVertexProgramConstantFloatCount(mCaps.MaxVertexShaderConst);
00738             break;
00739         default:
00740             mCapabilities->setMaxVertexProgramVersion("");
00741             break;
00742         }
00743 
00744         // populate syntax codes in program manager (no breaks in this one so it falls through)
00745         switch(major)
00746         {
00747         case 3:
00748             mGpuProgramManager->_pushSyntaxCode("vs_3_0");
00749         case 2:
00750             if (major > 2 || minor > 0)
00751                 mGpuProgramManager->_pushSyntaxCode("vs_2_x");
00752 
00753             mGpuProgramManager->_pushSyntaxCode("vs_2_0");
00754         case 1:
00755             mGpuProgramManager->_pushSyntaxCode("vs_1_1");
00756             mCapabilities->setCapability(RSC_VERTEX_PROGRAM);
00757         }
00758     }
00759     //---------------------------------------------------------------------
00760     void D3D9RenderSystem::convertPixelShaderCaps(void)
00761     {
00762         ushort major, minor;
00763         major = static_cast<ushort>((mCaps.PixelShaderVersion & 0x0000FF00) >> 8);
00764         minor = static_cast<ushort>(mCaps.PixelShaderVersion & 0x000000FF);
00765         switch (major)
00766         {
00767         case 1:
00768             switch(minor)
00769             {
00770             case 1:
00771                 mCapabilities->setMaxFragmentProgramVersion("ps_1_1");
00772                 break;
00773             case 2:
00774                 mCapabilities->setMaxFragmentProgramVersion("ps_1_2");
00775                 break;
00776             case 3:
00777                 mCapabilities->setMaxFragmentProgramVersion("ps_1_3");
00778                 break;
00779             case 4:
00780                 mCapabilities->setMaxFragmentProgramVersion("ps_1_4");
00781                 break;
00782             }
00783             break;
00784             // no boolean params allowed
00785             mCapabilities->setFragmentProgramConstantBoolCount(0);
00786             // no integer params allowed
00787             mCapabilities->setFragmentProgramConstantIntCount(0);
00788             // float params, always 4D
00789             // NB in ps_1_x these are actually stored as fixed point values,
00790             // but they are entered as floats
00791             mCapabilities->setFragmentProgramConstantFloatCount(8);
00792         case 2:
00793             if (minor > 0)
00794             {
00795                 mCapabilities->setMaxFragmentProgramVersion("ps_2_x");
00796                 // 16 boolean params allowed
00797                 mCapabilities->setFragmentProgramConstantBoolCount(16);
00798                 // 16 integer params allowed, 4D
00799                 mCapabilities->setFragmentProgramConstantIntCount(16);
00800                 // float params, always 4D
00801                 mCapabilities->setFragmentProgramConstantFloatCount(224);
00802             }
00803             else
00804             {
00805                 mCapabilities->setMaxFragmentProgramVersion("ps_2_0");
00806                 // no boolean params allowed
00807                 mCapabilities->setFragmentProgramConstantBoolCount(0);
00808                 // no integer params allowed
00809                 mCapabilities->setFragmentProgramConstantIntCount(0);
00810                 // float params, always 4D
00811                 mCapabilities->setFragmentProgramConstantFloatCount(32);
00812             }
00813             break;
00814         case 3:
00815             if (minor > 0)
00816             {
00817                 mCapabilities->setMaxFragmentProgramVersion("ps_3_x");
00818             }
00819             else
00820             {
00821                 mCapabilities->setMaxFragmentProgramVersion("ps_3_0");
00822             }
00823             // 16 boolean params allowed
00824             mCapabilities->setFragmentProgramConstantBoolCount(16);
00825             // 16 integer params allowed, 4D
00826             mCapabilities->setFragmentProgramConstantIntCount(16);
00827             // float params, always 4D
00828             mCapabilities->setFragmentProgramConstantFloatCount(224);
00829             break;
00830         default:
00831             mCapabilities->setMaxFragmentProgramVersion("");
00832             break;
00833         }
00834 
00835         // populate syntax codes in program manager (no breaks in this one so it falls through)
00836         switch(major)
00837         {
00838         case 3:
00839             if (minor > 0)
00840                 mGpuProgramManager->_pushSyntaxCode("ps_3_x");
00841 
00842             mGpuProgramManager->_pushSyntaxCode("ps_3_0");
00843         case 2:
00844             if (major > 2 || minor > 0)
00845                 mGpuProgramManager->_pushSyntaxCode("ps_2_x");
00846 
00847             mGpuProgramManager->_pushSyntaxCode("ps_2_0");
00848         case 1:
00849             if (major > 1 || minor >= 4)
00850                 mGpuProgramManager->_pushSyntaxCode("ps_1_4");
00851             if (major > 1 || minor >= 3)
00852                 mGpuProgramManager->_pushSyntaxCode("ps_1_3");
00853             if (major > 1 || minor >= 2)
00854                 mGpuProgramManager->_pushSyntaxCode("ps_1_2");
00855             
00856             mGpuProgramManager->_pushSyntaxCode("ps_1_1");
00857             mCapabilities->setCapability(RSC_FRAGMENT_PROGRAM);
00858         }
00859     }
00860     //---------------------------------------------------------------------
00861     RenderTexture * D3D9RenderSystem::createRenderTexture( const String & name, unsigned int width, unsigned int height )
00862     {
00863         RenderTexture *rt = new D3D9RenderTexture( name, width, height );
00864         attachRenderTarget( *rt );
00865         return rt;
00866     }
00867     //---------------------------------------------------------------------
00868     void D3D9RenderSystem::destroyRenderWindow( RenderWindow* pWin )
00869     {
00870         // Find it to remove from list
00871         RenderTargetMap::iterator i = mRenderTargets.begin();
00872 
00873         while( i->second != pWin && i != mRenderTargets.end() )
00874         {
00875             if( i->second == pWin )
00876             {
00877                 mRenderTargets.erase(i);
00878                 delete pWin;
00879                 break;
00880             }
00881         }
00882     }
00883     //---------------------------------------------------------------------
00884     String D3D9RenderSystem::getErrorDescription( long errorNumber ) const
00885     {
00886         const String errMsg = DXGetErrorDescription9( errorNumber );
00887         return errMsg;
00888     }
00889     //---------------------------------------------------------------------
00890     void D3D9RenderSystem::convertColourValue( const ColourValue& colour, unsigned long* pDest )
00891     {
00892         *pDest = colour.getAsLongARGB();
00893     }
00894     //---------------------------------------------------------------------
00895     void D3D9RenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane, 
00896         Real farPlane, Matrix4& dest, bool forGpuProgram)
00897     {
00898         Radian theta ( fovy * 0.5 );
00899         Real h = 1 / Math::Tan(theta);
00900         Real w = h / aspect;
00901         Real q, qn;
00902         if (farPlane == 0)
00903         {
00904             q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
00905             qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
00906         }
00907         else
00908         {
00909             q = farPlane / ( farPlane - nearPlane );
00910             qn = -q * nearPlane;
00911         }
00912 
00913         dest = Matrix4::ZERO;
00914         dest[0][0] = w;
00915         dest[1][1] = h;
00916 
00917         if (forGpuProgram)
00918         {
00919             dest[2][2] = -q;
00920             dest[3][2] = -1.0f;
00921         }
00922         else
00923         {
00924             dest[2][2] = q;
00925             dest[3][2] = 1.0f;
00926         }
00927 
00928         dest[2][3] = qn;
00929     }
00930     //---------------------------------------------------------------------
00931     void D3D9RenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane, 
00932         Matrix4& dest, bool forGpuProgram )
00933     {
00934         Radian thetaY (fovy / 2.0f);
00935         Real tanThetaY = Math::Tan(thetaY);
00936 
00937         //Real thetaX = thetaY * aspect;
00938         Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX);
00939         Real half_w = tanThetaX * nearPlane;
00940         Real half_h = tanThetaY * nearPlane;
00941         Real iw = 1.0 / half_w;
00942         Real ih = 1.0 / half_h;
00943         Real q;
00944         if (farPlane == 0)
00945         {
00946             q = 0;
00947         }
00948         else
00949         {
00950             q = 1.0 / (farPlane - nearPlane);
00951         }
00952 
00953         dest = Matrix4::ZERO;
00954         dest[0][0] = iw;
00955         dest[1][1] = ih;
00956         dest[2][2] = q;
00957         dest[2][3] = -nearPlane / (farPlane - nearPlane);
00958         dest[3][3] = 1;
00959 
00960         if (forGpuProgram)
00961         {
00962             dest[2][2] = -dest[2][2];
00963         }
00964     }
00965     //---------------------------------------------------------------------
00966     D3D9RenderSystem::ResizeRepositionWindow(HWND wich)
00967     {
00968         for (RenderTargetMap::iterator it = mRenderTargets.begin(); it != mRenderTargets.end(); ++it)
00969         {
00970             if (it->second->isActive())
00971             {
00972                 D3D9RenderWindow *pWin32Window = (D3D9RenderWindow *)it->second;
00973                 if (pWin32Window->getWindowHandle() == wich)
00974                 {
00975                     pWin32Window->WindowMovedOrResized();
00976                     break;
00977                 }
00978             }
00979         }
00980     }
00981     //---------------------------------------------------------------------
00982     void D3D9RenderSystem::setAmbientLight( float r, float g, float b )
00983     {
00984         HRESULT hr = __SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( r, g, b, 1.0f ) );
00985         if( FAILED( hr ) )
00986             Except( hr, "Failed to set render stat D3DRS_AMBIENT", "D3D9RenderSystem::setAmbientLight" );
00987     }
00988     //---------------------------------------------------------------------
00989     void D3D9RenderSystem::_useLights(const LightList& lights, unsigned short limit)
00990     {
00991         LightList::const_iterator i, iend;
00992         iend = lights.end();
00993         unsigned short num = 0;
00994         for (i = lights.begin(); i != iend && num < limit; ++i, ++num)
00995         {
00996             setD3D9Light(num, *i);
00997         }
00998         // Disable extra lights
00999         for (; num < mCurrentLights; ++num)
01000         {
01001             setD3D9Light(num, NULL);
01002         }
01003         mCurrentLights = std::min(limit, static_cast<unsigned short>(lights.size()));
01004 
01005     }
01006     //---------------------------------------------------------------------
01007     void D3D9RenderSystem::setShadingType( ShadeOptions so )
01008     {
01009         HRESULT hr = __SetRenderState( D3DRS_SHADEMODE, D3D9Mappings::get(so) );
01010         if( FAILED( hr ) )
01011             Except( hr, "Failed to set render stat D3DRS_SHADEMODE", "D3D9RenderSystem::setShadingType" );
01012     }
01013     //---------------------------------------------------------------------
01014     void D3D9RenderSystem::setLightingEnabled( bool enabled )
01015     {
01016         HRESULT hr;
01017         if( FAILED( hr = __SetRenderState( D3DRS_LIGHTING, enabled ) ) )
01018             Except( hr, "Failed to set render state D3DRS_LIGHTING", "D3D9RenderSystem::setLightingEnabled" );
01019     }
01020     //---------------------------------------------------------------------
01021     void D3D9RenderSystem::setD3D9Light( size_t index, Light* lt )
01022     {
01023         HRESULT hr;
01024 
01025         D3DLIGHT9 d3dLight;
01026         ZeroMemory( &d3dLight, sizeof(d3dLight) );
01027 
01028         if (!lt)
01029         {
01030             if( FAILED( hr = mpD3DDevice->LightEnable( index, FALSE) ) )
01031                 Except( hr, "Unable to disable light", "D3D9RenderSystem::setD3D9Light" );
01032         }
01033         else
01034         {
01035             switch( lt->getType() )
01036             {
01037             case Light::LT_POINT:
01038                 d3dLight.Type = D3DLIGHT_POINT;
01039                 break;
01040 
01041             case Light::LT_DIRECTIONAL:
01042                 d3dLight.Type = D3DLIGHT_DIRECTIONAL;
01043                 break;
01044 
01045             case Light::LT_SPOTLIGHT:
01046                 d3dLight.Type = D3DLIGHT_SPOT;
01047                 d3dLight.Falloff = lt->getSpotlightFalloff();
01048                 d3dLight.Theta = lt->getSpotlightInnerAngle().valueRadians();
01049                 d3dLight.Phi = lt->getSpotlightOuterAngle().valueRadians();
01050                 break;
01051             }
01052 
01053             ColourValue col;
01054             col = lt->getDiffuseColour();
01055             d3dLight.Diffuse = D3DXCOLOR( col.r, col.g, col.b, col.a );
01056 
01057             col = lt->getSpecularColour();
01058             d3dLight.Specular = D3DXCOLOR( col.r, col.g, col.b, col.a );
01059 
01060             Vector3 vec;
01061             if( lt->getType() != Light::LT_DIRECTIONAL )
01062             {
01063                 vec = lt->getDerivedPosition();
01064                 d3dLight.Position = D3DXVECTOR3( vec.x, vec.y, vec.z );
01065             }
01066             if( lt->getType() != Light::LT_POINT )
01067             {
01068                 vec = lt->getDerivedDirection();
01069                 d3dLight.Direction = D3DXVECTOR3( vec.x, vec.y, vec.z );
01070             }
01071 
01072             d3dLight.Range = lt->getAttenuationRange();
01073             d3dLight.Attenuation0 = lt->getAttenuationConstant();
01074             d3dLight.Attenuation1 = lt->getAttenuationLinear();
01075             d3dLight.Attenuation2 = lt->getAttenuationQuadric();
01076 
01077             if( FAILED( hr = mpD3DDevice->SetLight( index, &d3dLight ) ) )
01078                 Except( hr, "Unable to set light details", "D3D9RenderSystem::setD3D9Light" );
01079 
01080             if( FAILED( hr = mpD3DDevice->LightEnable( index, TRUE ) ) )
01081                 Except( hr, "Unable to enable light", "D3D9RenderSystem::setD3D9Light" );
01082         }
01083 
01084 
01085     }
01086     //---------------------------------------------------------------------
01087     void D3D9RenderSystem::_setViewMatrix( const Matrix4 &m )
01088     {
01089         // save latest view matrix
01090         mViewMatrix = m;
01091         mViewMatrix[2][0] = -mViewMatrix[2][0];
01092         mViewMatrix[2][1] = -mViewMatrix[2][1];
01093         mViewMatrix[2][2] = -mViewMatrix[2][2];
01094         mViewMatrix[2][3] = -mViewMatrix[2][3];
01095 
01096         D3DXMATRIX d3dmat = D3D9Mappings::makeD3DXMatrix( mViewMatrix );
01097 
01098         HRESULT hr;
01099         if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_VIEW, &d3dmat ) ) )
01100             Except( hr, "Cannot set D3D9 view matrix", "D3D9RenderSystem::_setViewMatrix" );
01101     }
01102     //---------------------------------------------------------------------
01103     void D3D9RenderSystem::_setProjectionMatrix( const Matrix4 &m )
01104     {
01105         D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
01106 
01107         if( mActiveRenderTarget->requiresTextureFlipping() )
01108             d3dMat._22 = - d3dMat._22;
01109 
01110         HRESULT hr;
01111         if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_PROJECTION, &d3dMat ) ) )
01112             Except( hr, "Cannot set D3D9 projection matrix", "D3D9RenderSystem::_setProjectionMatrix" );
01113     }
01114     //---------------------------------------------------------------------
01115     void D3D9RenderSystem::_setWorldMatrix( const Matrix4 &m )
01116     {
01117         D3DXMATRIX d3dMat = D3D9Mappings::makeD3DXMatrix( m );
01118 
01119         HRESULT hr;
01120         if( FAILED( hr = mpD3DDevice->SetTransform( D3DTS_WORLD, &d3dMat ) ) )
01121             Except( hr, "Cannot set D3D9 world matrix", "D3D9RenderSystem::_setWorldMatrix" );
01122     }
01123     //---------------------------------------------------------------------
01124     void D3D9RenderSystem::_setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse,
01125         const ColourValue &specular, const ColourValue &emissive, Real shininess )
01126     {
01127         // Remember last call
01128         static ColourValue lastAmbient = ColourValue::Black;
01129         static ColourValue lastDiffuse = ColourValue::Black;
01130         static ColourValue lastSpecular = ColourValue::Black;
01131         static ColourValue lastEmissive = ColourValue::Black;
01132         static Real lastShininess = 0.0;
01133 
01134         // Only update if changed
01135         if( ambient != lastAmbient || diffuse != lastDiffuse ||
01136             specular != lastSpecular || emissive != lastEmissive ||
01137             shininess != lastShininess )
01138         {
01139             D3DMATERIAL9 material;
01140             material.Diffuse = D3DXCOLOR( diffuse.r, diffuse.g, diffuse.b, diffuse.a );
01141             material.Ambient = D3DXCOLOR( ambient.r, ambient.g, ambient.b, ambient.a );
01142             material.Specular = D3DXCOLOR( specular.r, specular.g, specular.b, specular.a );
01143             material.Emissive = D3DXCOLOR( emissive.r, emissive.g, emissive.b, emissive.a );
01144             material.Power = shininess;
01145 
01146             HRESULT hr = mpD3DDevice->SetMaterial( &material );
01147             if( FAILED( hr ) )
01148                 Except( hr, "Error setting D3D material", "D3D9RenderSystem::_setSurfaceParams" );
01149 
01150             // Remember the details
01151             lastAmbient = ambient;
01152             lastDiffuse = diffuse;
01153             lastSpecular = specular;
01154             lastEmissive = emissive;
01155             lastShininess = shininess;
01156         }
01157     }
01158     //---------------------------------------------------------------------
01159     void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const String &texname )
01160     {
01161         HRESULT hr;
01162         D3D9Texture *dt = (D3D9Texture *)TextureManager::getSingleton().getByName(texname);
01163         if (enabled && dt)
01164         {
01165             IDirect3DBaseTexture9 *pTex = dt->getTexture();
01166             if (mTexStageDesc[stage].pTex != pTex)
01167             {
01168                 hr = mpD3DDevice->SetTexture(stage, pTex);
01169                 if( hr != S_OK )
01170                 {
01171                     String str = "Unable to set texture '" + texname + "' in D3D9";
01172                     Except( hr, str, "D3D9RenderSystem::_setTexture" );
01173                 }
01174                 
01175                 // set stage desc.
01176                 mTexStageDesc[stage].pTex = pTex;
01177                 mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
01178             }
01179         }
01180         else
01181         {
01182             if (mTexStageDesc[stage].pTex != 0)
01183             {
01184                 hr = mpD3DDevice->SetTexture(stage, 0);
01185                 if( hr != S_OK )
01186                 {
01187                     String str = "Unable to disable texture '" + texname + "' in D3D9";
01188                     Except( hr, str, "D3D9RenderSystem::_setTexture" );
01189                 }
01190             }
01191 
01192             hr = this->__SetTextureStageState(stage, D3DTSS_COLOROP, D3DTOP_DISABLE);
01193             if( hr != S_OK )
01194             {
01195                 String str = "Unable to disable texture '" + texname + "' in D3D9";
01196                 Except( hr, str, "D3D9RenderSystem::_setTexture" );
01197             }
01198 
01199             // set stage desc. to defaults
01200             mTexStageDesc[stage].pTex = 0;
01201             mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
01202             mTexStageDesc[stage].coordIndex = 0;
01203             mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
01204         }
01205     }
01206     //---------------------------------------------------------------------
01207     void D3D9RenderSystem::_setTextureCoordSet( size_t stage, size_t index )
01208     {
01209         HRESULT hr;
01210         // Record settings
01211         mTexStageDesc[stage].coordIndex = index;
01212 
01213         hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(mTexStageDesc[stage].autoTexCoordType, mCaps) | index );
01214         if( FAILED( hr ) )
01215             Except( hr, "Unable to set texture coord. set index", "D3D8RenderSystem::_setTextureCoordSet" );
01216     }
01217     //---------------------------------------------------------------------
01218     void D3D9RenderSystem::_setTextureCoordCalculation( size_t stage, TexCoordCalcMethod m,
01219         const Frustum* frustum)
01220     {
01221         HRESULT hr;
01222         // record the stage state
01223         mTexStageDesc[stage].autoTexCoordType = m;
01224         mTexStageDesc[stage].frustum = frustum;
01225 
01226         hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(m, mCaps) | mTexStageDesc[stage].coordIndex );
01227         if(FAILED(hr))
01228             Except( hr, "Unable to set texture auto tex.coord. generation mode", "D3D8RenderSystem::_setTextureCoordCalculation" );
01229     }
01230     //---------------------------------------------------------------------
01231     void D3D9RenderSystem::_setTextureMatrix( size_t stage, const Matrix4& xForm )
01232     {
01233         HRESULT hr;
01234         D3DXMATRIX d3dMatId; // ident. matrix in D3DX format
01235         D3DXMATRIX d3dMat; // the matrix we'll maybe apply
01236         Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format
01237         // make the ident. matrix in D3D format
01238         D3DXMatrixIdentity(&d3dMatId);
01239 
01240         if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_ENVIRONMENT_MAP)
01241         {
01242             if (mCaps.VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP)
01243             {
01245                 Matrix4 ogreMatEnvMap = Matrix4::IDENTITY;
01246                 // set env_map values
01247                 ogreMatEnvMap[1][1] = -1.0f;
01248                 // concatenate with the xForm
01249                 newMat = newMat.concatenate(ogreMatEnvMap);
01250             }
01251             else
01252             {
01253                 /* If envmap is applied, but device doesn't support spheremap,
01254                 then we have to use texture transform to make the camera space normal
01255                 reference the envmap properly. This isn't exactly the same as spheremap
01256                 (it looks nasty on flat areas because the camera space normals are the same)
01257                 but it's the best approximation we have in the absence of a proper spheremap */
01258                 // concatenate with the xForm
01259                 newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE);
01260             }
01261         }
01262 
01263         // If this is a cubic reflection, we need to modify using the view matrix
01264         if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION)
01265         {
01266             D3DXMATRIX viewMatrix; 
01267 
01268             // Get view matrix
01269             mpD3DDevice->GetTransform(D3DTS_VIEW, &viewMatrix);
01270             // Get transposed 3x3, ie since D3D is transposed just copy
01271             // We want to transpose since that will invert an orthonormal matrix ie rotation
01272             Matrix4 ogreViewTransposed;
01273             ogreViewTransposed[0][0] = viewMatrix.m[0][0];
01274             ogreViewTransposed[0][1] = viewMatrix.m[0][1];
01275             ogreViewTransposed[0][2] = viewMatrix.m[0][2];
01276             ogreViewTransposed[0][3] = 0.0f;
01277 
01278             ogreViewTransposed[1][0] = viewMatrix.m[1][0];
01279             ogreViewTransposed[1][1] = viewMatrix.m[1][1];
01280             ogreViewTransposed[1][2] = viewMatrix.m[1][2];
01281             ogreViewTransposed[1][3] = 0.0f;
01282 
01283             ogreViewTransposed[2][0] = viewMatrix.m[2][0];
01284             ogreViewTransposed[2][1] = viewMatrix.m[2][1];
01285             ogreViewTransposed[2][2] = viewMatrix.m[2][2];
01286             ogreViewTransposed[2][3] = 0.0f;
01287 
01288             ogreViewTransposed[3][0] = 0.0f;
01289             ogreViewTransposed[3][1] = 0.0f;
01290             ogreViewTransposed[3][2] = 0.0f;
01291             ogreViewTransposed[3][3] = 1.0f;
01292             
01293             newMat = newMat.concatenate(ogreViewTransposed);
01294         }
01295 
01296         if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
01297         {
01298             // Derive camera space to projector space transform
01299             // To do this, we need to undo the camera view matrix, then 
01300             // apply the projector view & projection matrices
01301             newMat = mViewMatrix.inverse() * newMat;
01302             newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat;
01303             newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat;
01304             if (mTexStageDesc[stage].frustum->getProjectionType() == PT_PERSPECTIVE)
01305             {
01306                 newMat = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * newMat;
01307             }
01308             else
01309             {
01310                 newMat = PROJECTIONCLIPSPACE2DTOIMAGESPACE_ORTHO * newMat;
01311             }
01312 
01313         }
01314 
01315         // convert our matrix to D3D format
01316         d3dMat = D3D9Mappings::makeD3DXMatrix(newMat);
01317 
01318         // need this if texture is a cube map, to invert D3D's z coord
01319         if (mTexStageDesc[stage].autoTexCoordType != TEXCALC_NONE)
01320         {
01321             d3dMat._13 = -d3dMat._13;
01322             d3dMat._23 = -d3dMat._23;
01323             d3dMat._33 = -d3dMat._33;
01324             d3dMat._43 = -d3dMat._43;
01325         }
01326 
01327         // set the matrix if it's not the identity
01328         if (d3dMat != d3dMatId)
01329         {
01330             // tell D3D the dimension of tex. coord.
01331             int texCoordDim;
01332             if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
01333             {
01334                 texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3;
01335             }
01336             else
01337             {
01338                 switch (mTexStageDesc[stage].texType)
01339                 {
01340                 case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
01341                     texCoordDim = D3DTTFF_COUNT2;
01342                     break;
01343                 case D3D9Mappings::D3D_TEX_TYPE_CUBE:
01344                 case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
01345                     texCoordDim = D3DTTFF_COUNT3;
01346                 }
01347             }
01348 
01349             hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim );
01350             if (FAILED(hr))
01351                 Except( hr, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" );
01352 
01353             hr = mpD3DDevice->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
01354             if (FAILED(hr))
01355                 Except( hr, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
01356         }
01357         else
01358         {
01359             // disable all of this
01360             hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
01361             if( FAILED( hr ) )
01362                 Except( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
01363 
01364             // set the identity matrix
01365             D3DXMatrixIdentity( &d3dMat );
01366             hr = mpD3DDevice->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
01367             if( FAILED( hr ) )
01368                 Except( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
01369         }
01370     }
01371     //---------------------------------------------------------------------
01372     void D3D9RenderSystem::_setTextureAddressingMode( size_t stage, TextureUnitState::TextureAddressingMode tam )
01373     {
01374         HRESULT hr;
01375         if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSU, D3D9Mappings::get(tam) ) ) )
01376             Except( hr, "Failed to set texture addressing mode for U", "D3D9RenderSystem::_setTextureAddressingMode" );
01377         if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSV, D3D9Mappings::get(tam) ) ) )
01378             Except( hr, "Failed to set texture addressing mode for V", "D3D9RenderSystem::_setTextureAddressingMode" );
01379         if( FAILED( hr = __SetSamplerState( stage, D3DSAMP_ADDRESSW, D3D9Mappings::get(tam) ) ) )
01380             Except( hr, "Failed to set texture addressing mode for W", "D3D9RenderSystem::_setTextureAddressingMode" );
01381     }
01382     //---------------------------------------------------------------------
01383     void D3D9RenderSystem::_setTextureBlendMode( size_t stage, const LayerBlendModeEx& bm )
01384     {
01385         HRESULT hr = S_OK;
01386         D3DTEXTURESTAGESTATETYPE tss;
01387         D3DCOLOR manualD3D;
01388 
01389         // choose type of blend.
01390         if( bm.blendType == LBT_COLOUR )
01391             tss = D3DTSS_COLOROP;
01392         else if( bm.blendType == LBT_ALPHA )
01393             tss = D3DTSS_ALPHAOP;
01394         // set manual factor if required by operation
01395         if (bm.operation == LBX_BLEND_MANUAL)
01396         {
01397             hr = __SetRenderState( D3DRS_TEXTUREFACTOR, D3DXCOLOR(0.0, 0.0, 0.0,  bm.factor) );
01398             if (FAILED(hr))
01399                 Except( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
01400         }
01401         // set operation
01402         hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.operation, mCaps) );
01403         if (FAILED(hr))
01404             Except( hr, "Failed to set operation", "D3D9RenderSystem::_setTextureBlendMode" );
01405 
01406         // choose source 1
01407         if( bm.blendType == LBT_COLOUR )
01408         {
01409             tss = D3DTSS_COLORARG1;
01410             manualD3D = D3DXCOLOR( bm.colourArg1.r, bm.colourArg1.g, bm.colourArg1.b, bm.colourArg1.a );
01411         }
01412         else if( bm.blendType == LBT_ALPHA )
01413         {
01414             tss = D3DTSS_ALPHAARG1;
01415             manualD3D = D3DXCOLOR( 0.0, 0.0, 0.0, bm.alphaArg1 );
01416         }
01417         // Set manual factor if required
01418         if (bm.source1 == LBS_MANUAL)
01419         {
01420             hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
01421             if (FAILED(hr))
01422                 Except( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
01423         }
01424         // set source 1
01425         hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source1) );
01426         if (FAILED(hr))
01427             Except( hr, "Failed to set source1", "D3D9RenderSystem::_setTextureBlendMode" );
01428         
01429         // choose source 2
01430         if( bm.blendType == LBT_COLOUR )
01431         {
01432             tss = D3DTSS_COLORARG2;
01433             manualD3D = D3DXCOLOR( bm.colourArg2.r, bm.colourArg2.g, bm.colourArg2.b, bm.colourArg2.a );
01434         }
01435         else if( bm.blendType == LBT_ALPHA )
01436         {
01437             tss = D3DTSS_ALPHAARG2;
01438             manualD3D = D3DXCOLOR( 0.0, 0.0, 0.0, bm.alphaArg2 );
01439         }
01440         // Set manual factor if required
01441         if (bm.source2 == LBS_MANUAL)
01442         {
01443             hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
01444             if (FAILED(hr))
01445                 Except( hr, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
01446         }
01447         // Now set source 2
01448         hr = __SetTextureStageState( stage, tss, D3D9Mappings::get(bm.source2) );
01449         if (FAILED(hr))
01450             Except( hr, "Failed to set source 2", "D3D9RenderSystem::_setTextureBlendMode" );
01451     }
01452     //---------------------------------------------------------------------
01453     void D3D9RenderSystem::_setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor )
01454     {
01455         HRESULT hr;
01456         if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
01457             Except( hr, "Failed to set source blend", "D3D9RenderSystem::_setSceneBlending" );
01458         if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
01459             Except( hr, "Failed to set destination blend", "D3D9RenderSystem::_setSceneBlending" );
01460     }
01461     //---------------------------------------------------------------------
01462     void D3D9RenderSystem::_setAlphaRejectSettings( CompareFunction func, unsigned char value )
01463     {
01464         HRESULT hr;
01465         if (func != CMPF_ALWAYS_PASS)
01466         {
01467             if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE ) ) )
01468                 Except( hr, "Failed to enable alpha testing", 
01469                 "D3D9RenderSystem::_setAlphaRejectSettings" );
01470         }
01471         else
01472         {
01473             if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE ) ) )
01474                 Except( hr, "Failed to disable alpha testing", 
01475                 "D3D9RenderSystem::_setAlphaRejectSettings" );
01476         }
01477         // Set always just be sure
01478         if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) )
01479             Except( hr, "Failed to set alpha reject function", "D3D9RenderSystem::_setAlphaRejectSettings" );
01480         if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) )
01481             Except( hr, "Failed to set render state D3DRS_ALPHAREF", "D3D9RenderSystem::_setAlphaRejectSettings" );
01482     }
01483     //---------------------------------------------------------------------
01484     void D3D9RenderSystem::_setCullingMode( CullingMode mode )
01485     {
01486         HRESULT hr;
01487         bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
01488                 (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding));
01489 
01490         if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE, 
01491             D3D9Mappings::get(mode, flip))) )
01492             Except( hr, "Failed to set culling mode", "D3D9RenderSystem::_setCullingMode" );
01493     }
01494     //---------------------------------------------------------------------
01495     void D3D9RenderSystem::_setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction )
01496     {
01497         _setDepthBufferCheckEnabled( depthTest );
01498         _setDepthBufferWriteEnabled( depthWrite );
01499         _setDepthBufferFunction( depthFunction );
01500     }
01501     //---------------------------------------------------------------------
01502     void D3D9RenderSystem::_setDepthBufferCheckEnabled( bool enabled )
01503     {
01504         HRESULT hr;
01505 
01506         if( enabled )
01507         {
01508             // Use w-buffer if available and enabled
01509             if( mWBuffer && mCaps.RasterCaps & D3DPRASTERCAPS_WBUFFER )
01510                 hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
01511             else
01512                 hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
01513         }
01514         else
01515             hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
01516 
01517         if( FAILED( hr ) )
01518             Except( hr, "Error setting depth buffer test state", "D3D9RenderSystem::_setDepthBufferCheckEnabled" );
01519     }
01520     //---------------------------------------------------------------------
01521     void D3D9RenderSystem::_setDepthBufferWriteEnabled( bool enabled )
01522     {
01523         HRESULT hr;
01524 
01525         if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) )
01526             Except( hr, "Error setting depth buffer write state", "D3D9RenderSystem::_setDepthBufferWriteEnabled" );
01527     }
01528     //---------------------------------------------------------------------
01529     void D3D9RenderSystem::_setDepthBufferFunction( CompareFunction func )
01530     {
01531         HRESULT hr;
01532         if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) )
01533             Except( hr, "Error setting depth buffer test function", "D3D9RenderSystem::_setDepthBufferFunction" );
01534     }
01535     //---------------------------------------------------------------------
01536     void D3D9RenderSystem::_setDepthBias(ushort bias)
01537     {
01538         HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, bias);
01539         if (FAILED(hr))
01540             Except(hr, "Error setting depth bias", "D3D9RenderSystem::_setDepthBias");
01541     }
01542     //---------------------------------------------------------------------
01543     void D3D9RenderSystem::_setColourBufferWriteEnabled(bool red, bool green, 
01544         bool blue, bool alpha)
01545     {
01546         DWORD val = 0;
01547         if (red) 
01548             val |= D3DCOLORWRITEENABLE_RED;
01549         if (green)
01550             val |= D3DCOLORWRITEENABLE_GREEN;
01551         if (blue)
01552             val |= D3DCOLORWRITEENABLE_BLUE;
01553         if (alpha)
01554             val |= D3DCOLORWRITEENABLE_ALPHA;
01555         HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val); 
01556         if (FAILED(hr))
01557             Except(hr, "Error setting colour write enable flags", 
01558             "D3D9RenderSystem::_setColourBufferWriteEnabled");
01559     }
01560     //---------------------------------------------------------------------
01561     void D3D9RenderSystem::_setFog( FogMode mode, const ColourValue& colour, Real densitiy, Real start, Real end )
01562     {
01563         HRESULT hr;
01564 
01565         D3DRENDERSTATETYPE fogType, fogTypeNot;
01566 
01567         if (mCaps.RasterCaps & D3DPRASTERCAPS_FOGTABLE)
01568         {
01569             fogType = D3DRS_FOGTABLEMODE;
01570             fogTypeNot = D3DRS_FOGVERTEXMODE;
01571         }
01572         else
01573         {
01574             fogType = D3DRS_FOGVERTEXMODE;
01575             fogTypeNot = D3DRS_FOGTABLEMODE;
01576         }
01577 
01578         if( mode == FOG_NONE)
01579         {
01580             // just disable
01581             hr = __SetRenderState(fogType, D3DFOG_NONE );
01582             hr = __SetRenderState(D3DRS_FOGENABLE, FALSE);
01583         }
01584         else
01585         {
01586             // Allow fog
01587             hr = __SetRenderState( D3DRS_FOGENABLE, TRUE );
01588             hr = __SetRenderState( fogTypeNot, D3DFOG_NONE );
01589             hr = __SetRenderState( fogType, D3D9Mappings::get(mode) );
01590 
01591             hr = __SetRenderState( D3DRS_FOGCOLOR, colour.getAsLongARGB() );
01592             hr = __SetRenderState( D3DRS_FOGSTART, *((LPDWORD)(&start)) );
01593             hr = __SetRenderState( D3DRS_FOGEND, *((LPDWORD)(&end)) );
01594             hr = __SetRenderState( D3DRS_FOGDENSITY, *((LPDWORD)(&densitiy)) );
01595         }
01596 
01597         if( FAILED( hr ) )
01598             Except( hr, "Error setting render state", "D3D9RenderSystem::_setFog" );
01599     }
01600     //---------------------------------------------------------------------
01601     void D3D9RenderSystem::_setRasterisationMode(SceneDetailLevel level)
01602     {
01603         HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level));
01604         if (FAILED(hr))
01605             Except(hr, "Error setting rasterisation mode.", "D3D9RenderSystem::setRasterisationMode");
01606     }
01607     //---------------------------------------------------------------------
01608     void D3D9RenderSystem::setStencilCheckEnabled(bool enabled)
01609     {
01610         // Allow stencilling
01611         HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled);
01612         if (FAILED(hr))
01613             Except(hr, "Error enabling / disabling stencilling.",
01614             "D3D9RenderSystem::setStencilCheckEnabled");
01615     }
01616     //---------------------------------------------------------------------
01617     void D3D9RenderSystem::setStencilBufferParams(CompareFunction func, ulong refValue, 
01618         ulong mask, StencilOperation stencilFailOp, 
01619         StencilOperation depthFailOp, StencilOperation passOp, 
01620         bool twoSidedOperation)
01621     {
01622         HRESULT hr;
01623 
01624         // 2-sided operation
01625         if (twoSidedOperation)
01626         {
01627             if (!mCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL))
01628                 Except(Exception::ERR_INVALIDPARAMS, "2-sided stencils are not supported",
01629                     "D3D9RenderSystem::setStencilBufferParams");
01630             hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
01631             if (FAILED(hr))
01632                 Except(hr, "Error setting 2-sided stencil mode.",
01633                 "D3D9RenderSystem::setStencilBufferParams");
01634 
01635             // Set alternative versions of ops
01636             // fail op
01637             hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, true));
01638             if (FAILED(hr))
01639                 Except(hr, "Error setting stencil fail operation (2-sided).",
01640                 "D3D9RenderSystem::setStencilBufferParams");
01641 
01642             // depth fail op
01643             hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, true));
01644             if (FAILED(hr))
01645                 Except(hr, "Error setting stencil depth fail operation (2-sided).",
01646                 "D3D9RenderSystem::setStencilBufferParams");
01647 
01648             // pass op
01649             hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, true));
01650             if (FAILED(hr))
01651                 Except(hr, "Error setting stencil pass operation (2-sided).",
01652                 "D3D9RenderSystem::setStencilBufferParams");
01653 
01654         }
01655         else
01656         {
01657             hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
01658             if (FAILED(hr))
01659                 Except(hr, "Error setting 1-sided stencil mode.",
01660                 "D3D9RenderSystem::setStencilBufferParams");
01661         }
01662 
01663         // func
01664         hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func));
01665         if (FAILED(hr))
01666             Except(hr, "Error setting stencil buffer test function.",
01667             "D3D9RenderSystem::setStencilBufferParams");
01668 
01669         // reference value
01670         hr = __SetRenderState(D3DRS_STENCILREF, refValue);
01671         if (FAILED(hr))
01672             Except(hr, "Error setting stencil buffer reference value.",
01673             "D3D9RenderSystem::setStencilBufferParams");
01674 
01675         // mask
01676         hr = __SetRenderState(D3DRS_STENCILMASK, mask);
01677         if (FAILED(hr))
01678             Except(hr, "Error setting stencil buffer mask.",
01679             "D3D9RenderSystem::setStencilBufferParams");
01680 
01681         // fail op
01682         hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp));
01683         if (FAILED(hr))
01684             Except(hr, "Error setting stencil fail operation.",
01685             "D3D9RenderSystem::setStencilBufferParams");
01686 
01687         // depth fail op
01688         hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp));
01689         if (FAILED(hr))
01690             Except(hr, "Error setting stencil depth fail operation.",
01691             "D3D9RenderSystem::setStencilBufferParams");
01692 
01693         // pass op
01694         hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp));
01695         if (FAILED(hr))
01696             Except(hr, "Error setting stencil pass operation.",
01697             "D3D9RenderSystem::setStencilBufferParams");
01698     }
01699     //---------------------------------------------------------------------
01700     void D3D9RenderSystem::_setTextureUnitFiltering(size_t unit, FilterType ftype, 
01701         FilterOptions filter)
01702     {
01703         HRESULT hr;
01704         D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType;
01705         hr = __SetSamplerState( unit, D3D9Mappings::get(ftype), 
01706             D3D9Mappings::get(ftype, filter, mCaps, texType));
01707         if (FAILED(hr))
01708             Except(hr, "Failed to set texture filter ", "D3D9RenderSystem::_setTextureUnitFiltering");
01709     }
01710     //---------------------------------------------------------------------
01711     DWORD D3D9RenderSystem::_getCurrentAnisotropy(size_t unit)
01712     {
01713         DWORD oldVal;
01714         mpD3DDevice->GetSamplerState(unit, D3DSAMP_MAXANISOTROPY, &oldVal);
01715             return oldVal;
01716     }
01717     //---------------------------------------------------------------------
01718     void D3D9RenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy)
01719     {
01720         if ((DWORD)maxAnisotropy > mCaps.MaxAnisotropy)
01721             maxAnisotropy = mCaps.MaxAnisotropy;
01722 
01723         if (_getCurrentAnisotropy(unit) != maxAnisotropy)
01724             __SetSamplerState( unit, D3DSAMP_MAXANISOTROPY, maxAnisotropy );
01725     }
01726     //---------------------------------------------------------------------
01727     HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
01728     {
01729         HRESULT hr;
01730         DWORD oldVal;
01731 
01732         if ( FAILED( hr = mpD3DDevice->GetRenderState(state, &oldVal) ) )
01733             return hr;
01734         if ( oldVal == value )
01735             return D3D_OK;
01736         else
01737             return mpD3DDevice->SetRenderState(state, value);
01738     }
01739     //---------------------------------------------------------------------
01740     HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
01741     {
01742         HRESULT hr;
01743         DWORD oldVal;
01744 
01745         if ( FAILED( hr = mpD3DDevice->GetSamplerState(sampler, type, &oldVal) ) )
01746             return hr;
01747         if ( oldVal == value )
01748             return D3D_OK;
01749         else
01750             return mpD3DDevice->SetSamplerState(sampler, type, value);
01751     }
01752     //---------------------------------------------------------------------
01753     HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
01754     {
01755         HRESULT hr;
01756         DWORD oldVal;
01757         
01758         if ( FAILED( hr = mpD3DDevice->GetTextureStageState(stage, type, &oldVal) ) )
01759             return hr;
01760         if ( oldVal == value )
01761             return D3D_OK;
01762         else
01763             return mpD3DDevice->SetTextureStageState(stage, type, value);
01764     }
01765     //---------------------------------------------------------------------
01766     void D3D9RenderSystem::_setViewport( Viewport *vp )
01767     {
01768         if( vp != mActiveViewport || vp->_isUpdated() )
01769         {
01770             mActiveViewport = vp;
01771             mActiveRenderTarget = vp->getTarget();
01772 
01773             // ok, it's different, time to set render target and viewport params
01774             D3DVIEWPORT9 d3dvp;
01775             HRESULT hr;
01776 
01777             // Set render target
01778             RenderTarget* target;
01779             target = vp->getTarget();
01780 
01781             LPDIRECT3DSURFACE9 pBack = NULL;
01782             target->getCustomAttribute( "DDBACKBUFFER", &pBack );
01783             if (!pBack)
01784                 return;
01785 
01786             LPDIRECT3DSURFACE9 pDepth = NULL;
01787             target->getCustomAttribute( "D3DZBUFFER", &pDepth );
01788             if (!pDepth)
01789                 return;
01790             
01791             hr = mpD3DDevice->SetRenderTarget(0, pBack);
01792             if (FAILED(hr))
01793             {
01794                 String msg = DXGetErrorDescription9(hr);
01795                 Except( hr, "Failed to setRenderTarget : " + msg, "D3D9RenderSystem::_setViewport" );
01796             }
01797             hr = mpD3DDevice->SetDepthStencilSurface(pDepth);
01798             if (FAILED(hr))
01799             {
01800                 String msg = DXGetErrorDescription9(hr);
01801                 Except( hr, "Failed to setDepthStencil : " + msg, "D3D9RenderSystem::_setViewport" );
01802             }
01803 
01804             _setCullingMode( mCullingMode );
01805 
01806             // set viewport dimensions
01807             d3dvp.X = vp->getActualLeft();
01808             d3dvp.Y = vp->getActualTop();
01809             d3dvp.Width = vp->getActualWidth();
01810             d3dvp.Height = vp->getActualHeight();
01811 
01812             // Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
01813             d3dvp.MinZ = 0.0f;
01814             d3dvp.MaxZ = 1.0f;
01815 
01816             if( FAILED( hr = mpD3DDevice->SetViewport( &d3dvp ) ) )
01817                 Except( hr, "Failed to set viewport.", "D3D9RenderSystem::_setViewport" );
01818 
01819             vp->_clearUpdatedFlag();
01820         }
01821     }
01822     //---------------------------------------------------------------------
01823     void D3D9RenderSystem::_beginFrame()
01824     {
01825         OgreGuard( "D3D9RenderSystem::_beginFrame" );
01826 
01827         HRESULT hr;
01828 
01829         if( !mActiveViewport )
01830             Except( Exception::ERR_INTERNAL_ERROR, "Cannot begin frame - no viewport selected.", "D3D9RenderSystem::_beginFrame" );
01831 
01832         // Clear the viewport if required
01833         if( mActiveViewport->getClearEveryFrame() )
01834         {
01835             clearFrameBuffer(FBT_COLOUR | FBT_DEPTH, 
01836                 mActiveViewport->getBackgroundColour());
01837         }
01838 
01839         if( FAILED( hr = mpD3DDevice->BeginScene() ) )
01840         {
01841             String msg = DXGetErrorDescription9(hr);
01842             Except( hr, "Error beginning frame :" + msg, "D3D9RenderSystem::_beginFrame" );
01843         }
01844 
01845         static bool firstTime = true;
01846         if( firstTime )
01847         {
01848             // First-time 
01849             // setup some defaults
01850             // Allow alpha blending
01851             hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
01852             if (FAILED(hr))
01853             {
01854                 String msg = DXGetErrorDescription9(hr);
01855                 Except(hr, "Error enabling alpha blending option : " + msg, "D3D9RenderSystem::_beginFrame");
01856             }
01857             // Allow specular
01858             hr = __SetRenderState(D3DRS_SPECULARENABLE, TRUE);
01859             if (FAILED(hr))
01860             {
01861                 String msg = DXGetErrorDescription9(hr);
01862                 Except(hr, "Error enabling alpha blending option : " + msg, "D3D9RenderSystem::_beginFrame");
01863             }
01864             firstTime = false;
01865         }
01866 
01867         OgreUnguard();
01868     }
01869     //---------------------------------------------------------------------
01870     void D3D9RenderSystem::_endFrame()
01871     {
01872         OgreGuard( "D3D9RenderSystem::_endFrame" );
01873 
01874         HRESULT hr;
01875         if( FAILED( hr = mpD3DDevice->EndScene() ) )
01876             Except( hr, "Error ending frame", "D3D9RenderSystem::_endFrame" );
01877 
01878         OgreUnguard();
01879     }
01880     //---------------------------------------------------------------------
01881     inline bool D3D9RenderSystem::compareDecls( D3DVERTEXELEMENT9* pDecl1, D3DVERTEXELEMENT9* pDecl2, size_t size )
01882     {
01883         for( size_t i=0; i < size; i++ )
01884         {
01885             if( pDecl1[i].Method != pDecl2[i].Method ||
01886                 pDecl1[i].Offset != pDecl2[i].Offset ||
01887                 pDecl1[i].Stream != pDecl2[i].Stream ||
01888                 pDecl1[i].Type != pDecl2[i].Type ||
01889                 pDecl1[i].Usage != pDecl2[i].Usage ||
01890                 pDecl1[i].UsageIndex != pDecl2[i].UsageIndex)
01891             {
01892                 return false;
01893             }
01894         }
01895 
01896         return true;
01897     }
01898     //---------------------------------------------------------------------
01899     void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl)
01900     {
01901         // Guard
01902         OgreGuard ("D3D9RenderSystem::setVertexDeclaration");
01903         HRESULT hr;
01904 
01905         D3D9VertexDeclaration* d3ddecl = 
01906             static_cast<D3D9VertexDeclaration*>(decl);
01907 
01908         static VertexDeclaration* lastDecl = 0;
01909 
01910         // attempt to detect duplicates
01911         if (!lastDecl || !(*lastDecl == *decl))
01912         {
01913 
01914             if (FAILED(hr = mpD3DDevice->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration())))
01915             {
01916                 Except(hr, "Unable to set D3D9 vertex declaration", 
01917                     "D3D9RenderSystem::setVertexDeclaration");
01918             }
01919         }
01920 
01921         // UnGuard
01922         OgreUnguard();
01923     }
01924     //---------------------------------------------------------------------
01925     void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
01926     {
01927         // Guard
01928         OgreGuard ("D3D9RenderSystem::setVertexBufferBinding");
01929 
01930         HRESULT hr;
01931 
01932         // TODO: attempt to detect duplicates
01933         const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings();
01934         VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend;
01935         iend = binds.end();
01936         for (i = binds.begin(); i != iend; ++i)
01937         {
01938             const D3D9HardwareVertexBuffer* d3d9buf = 
01939                 static_cast<const D3D9HardwareVertexBuffer*>(i->second.get());
01940             hr = mpD3DDevice->SetStreamSource(
01941                 static_cast<UINT>(i->first),
01942                 d3d9buf->getD3D9VertexBuffer(),
01943                 0, // no stream offset, this is handled in _render instead
01944                 static_cast<UINT>(d3d9buf->getVertexSize()) // stride
01945                 );
01946             if (FAILED(hr))
01947             {
01948                 Except(hr, "Unable to set D3D9 stream source for buffer binding", 
01949                     "D3D9RenderSystem::setVertexBufferBinding");
01950             }
01951 
01952 
01953         }
01954 
01955         // Unbind any unused sources
01956         for (size_t unused = binds.size(); unused < mLastVertexSourceCount; ++unused)
01957         {
01958             
01959             hr = mpD3DDevice->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0);
01960             if (FAILED(hr))
01961             {
01962                 Except(hr, "Unable to reset unused D3D9 stream source", 
01963                     "D3D9RenderSystem::setVertexBufferBinding");
01964             }
01965             
01966         }
01967         mLastVertexSourceCount = binds.size();
01968         
01969 
01970         
01971         // UnGuard
01972         OgreUnguard();
01973     }
01974     //---------------------------------------------------------------------
01975     void D3D9RenderSystem::_render(const RenderOperation& op)
01976     {
01977         // Guard
01978         OgreGuard ("D3D9RenderSystem::_render");
01979 
01980         // Exit immediately if there is nothing to render
01981         // This caused a problem on FireGL 8800
01982         if (op.vertexData->vertexCount == 0)
01983             return;
01984 
01985         // Call super class
01986         RenderSystem::_render(op);
01987 
01988         // To think about: possibly remove setVertexDeclaration and 
01989         // setVertexBufferBinding from RenderSystem since the sequence is
01990         // a bit too D3D9-specific?
01991         setVertexDeclaration(op.vertexData->vertexDeclaration);
01992         setVertexBufferBinding(op.vertexData->vertexBufferBinding);
01993 
01994         // Determine rendering operation
01995         D3DPRIMITIVETYPE primType;
01996         DWORD primCount = 0;
01997         switch( op.operationType )
01998         {
01999         case RenderOperation::OT_POINT_LIST:
02000             primType = D3DPT_POINTLIST;
02001             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount);
02002             break;
02003 
02004         case RenderOperation::OT_LINE_LIST:
02005             primType = D3DPT_LINELIST;
02006             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2;
02007             break;
02008 
02009         case RenderOperation::OT_LINE_STRIP:
02010             primType = D3DPT_LINESTRIP;
02011             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1;
02012             break;
02013 
02014         case RenderOperation::OT_TRIANGLE_LIST:
02015             primType = D3DPT_TRIANGLELIST;
02016             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3;
02017             break;
02018 
02019         case RenderOperation::OT_TRIANGLE_STRIP:
02020             primType = D3DPT_TRIANGLESTRIP;
02021             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
02022             break;
02023 
02024         case RenderOperation::OT_TRIANGLE_FAN:
02025             primType = D3DPT_TRIANGLEFAN;
02026             primCount = (DWORD)(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
02027             break;
02028         }
02029 
02030         if (!primCount)
02031             return;
02032 
02033         // Issue the op
02034         HRESULT hr;
02035         if( op.useIndexes )
02036         {
02037             D3D9HardwareIndexBuffer* d3dIdxBuf = 
02038                 static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get());
02039             hr = mpD3DDevice->SetIndices( d3dIdxBuf->getD3DIndexBuffer() );
02040             if (FAILED(hr))
02041             {
02042                 Except( hr, "Failed to set index buffer", "D3D9RenderSystem::_render" );
02043             }
02044 
02045             // do indexed draw operation
02046             hr = mpD3DDevice->DrawIndexedPrimitive(
02047                 primType, 
02048                 static_cast<INT>(op.vertexData->vertexStart), 
02049                 0, // Min vertex index - assume we can go right down to 0 
02050                 static_cast<UINT>(op.vertexData->vertexCount), 
02051                 static_cast<UINT>(op.indexData->indexStart), 
02052                 static_cast<UINT>(primCount)
02053                 );
02054         }
02055         else
02056         {
02057             // Unindexed, a little simpler!
02058             hr = mpD3DDevice->DrawPrimitive(
02059                 primType, 
02060                 static_cast<UINT>(op.vertexData->vertexStart), 
02061                 static_cast<UINT>(primCount)
02062                 ); 
02063         }
02064 
02065         if( FAILED( hr ) )
02066         {
02067             String msg = DXGetErrorDescription9(hr);
02068             Except( hr, "Failed to DrawPrimitive : " + msg, "D3D9RenderSystem::_render" );
02069         }
02070         
02071         // UnGuard
02072         OgreUnguard();
02073 
02074     }
02075     //---------------------------------------------------------------------
02076     void D3D9RenderSystem::setNormaliseNormals(bool normalise)
02077     {
02078         __SetRenderState(D3DRS_NORMALIZENORMALS, 
02079             normalise ? TRUE : FALSE);
02080     }
02081     //---------------------------------------------------------------------
02082     void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg)
02083     {
02084         HRESULT hr;
02085         switch (prg->getType())
02086         {
02087         case GPT_VERTEX_PROGRAM:
02088             hr = mpD3DDevice->SetVertexShader(
02089                 static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader());
02090             if (FAILED(hr))
02091             {
02092                 Except(hr, "Error calling SetVertexShader", "D3D9RenderSystem::bindGpuProgram");
02093             }
02094             break;
02095         case GPT_FRAGMENT_PROGRAM:
02096             hr = mpD3DDevice->SetPixelShader(
02097                 static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader());
02098             if (FAILED(hr))
02099             {
02100                 Except(hr, "Error calling SetPixelShader", "D3D9RenderSystem::bindGpuProgram");
02101             }
02102             break;
02103         };
02104 
02105     }
02106     //---------------------------------------------------------------------
02107     void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
02108     {
02109         HRESULT hr;
02110         switch(gptype)
02111         {
02112         case GPT_VERTEX_PROGRAM:
02113             hr = mpD3DDevice->SetVertexShader(NULL);
02114             if (FAILED(hr))
02115             {
02116                 Except(hr, "Error resetting SetVertexShader to NULL", 
02117                     "D3D9RenderSystem::unbindGpuProgram");
02118             }
02119             break;
02120         case GPT_FRAGMENT_PROGRAM:
02121             hr = mpD3DDevice->SetPixelShader(NULL);
02122             if (FAILED(hr))
02123             {
02124                 Except(hr, "Error resetting SetPixelShader to NULL", 
02125                     "D3D9RenderSystem::unbindGpuProgram");
02126             }
02127             break;
02128         };
02129     }
02130     //---------------------------------------------------------------------
02131     void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype, 
02132         GpuProgramParametersSharedPtr params)
02133     {
02134         HRESULT hr;
02135         unsigned int index;
02136         GpuProgramParameters::IntConstantIterator intIt = params->getIntConstantIterator();
02137         GpuProgramParameters::RealConstantIterator realIt = params->getRealConstantIterator();
02138 
02139         switch(gptype)
02140         {
02141         case GPT_VERTEX_PROGRAM:
02142             // Bind floats
02143             if (params->hasRealConstantParams())
02144             {
02145                 // Iterate over params and set the relevant ones
02146                 index = 0;
02147                 while (realIt.hasMoreElements())
02148                 {
02149                     const GpuProgramParameters::RealConstantEntry* e = realIt.peekNextPtr();
02150                     if (e->isSet)
02151                     {
02152                         if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantF(
02153                             index, e->val, 1)))
02154                         {
02155                             Except(hr, "Unable to upload shader float parameters", 
02156                                 "D3D9RenderSystem::bindGpuProgramParameters");
02157                         }
02158                     }
02159                     index++;
02160                     realIt.moveNext();
02161                 }
02162             }
02163             // Bind ints
02164             if (params->hasIntConstantParams())
02165             {
02166                 // Iterate over params and set the relevant ones
02167                 index = 0;
02168                 while (intIt.hasMoreElements())
02169                 {
02170                     const GpuProgramParameters::IntConstantEntry* e = intIt.peekNextPtr();
02171                     if (e->isSet)
02172                     {
02173                         if (FAILED(hr = mpD3DDevice->SetVertexShaderConstantI(
02174                             index, e->val, 1)))
02175                         {
02176                             Except(hr, "Unable to upload shader float parameters", 
02177                                 "D3D9RenderSystem::bindGpuProgramParameters");
02178                         }
02179                     }
02180                     index++;
02181                     intIt.moveNext();
02182                 }
02183             }
02184             break;
02185         case GPT_FRAGMENT_PROGRAM:
02186             // Bind floats
02187             if (params->hasRealConstantParams())
02188             {
02189                 // Iterate over params and set the relevant ones
02190                 index = 0;
02191                 while (realIt.hasMoreElements())
02192                 {
02193                     const GpuProgramParameters::RealConstantEntry* e = realIt.peekNextPtr();
02194                     if (e->isSet)
02195                     {
02196                         /*
02197                         // TEST
02198                         LogManager::getSingleton().logMessage(
02199                             "  Set Constant " + StringConverter::toString(index) + " to float4(" +
02200                             StringConverter::toString(e->val[0]) + ", " + 
02201                             StringConverter::toString(e->val[1]) + ", " + 
02202                             StringConverter::toString(e->val[2]) + ", " + 
02203                             StringConverter::toString(e->val[3]) + ")"); 
02204                         */
02205 
02206                         if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantF(
02207                             index, e->val, 1)))
02208                         {
02209                             Except(hr, "Unable to upload shader float parameters", 
02210                                 "D3D9RenderSystem::bindGpuProgramParameters");
02211                         }
02212                     }
02213                     index++;
02214                     realIt.moveNext();
02215                 }
02216             }
02217             // Bind ints
02218             if (params->hasIntConstantParams())
02219             {
02220                 // Iterate over params and set the relevant ones
02221                 index = 0;
02222                 while (intIt.hasMoreElements())
02223                 {
02224                     const GpuProgramParameters::IntConstantEntry* e = intIt.peekNextPtr();
02225                     if (e->isSet)
02226                     {
02227                         if (FAILED(hr = mpD3DDevice->SetPixelShaderConstantI(
02228                             index, e->val, 1)))
02229                         {
02230                             Except(hr, "Unable to upload shader float parameters", 
02231                                 "D3D9RenderSystem::bindGpuProgramParameters");
02232                         }
02233                     }
02234                     index++;
02235                     intIt.moveNext();
02236                 }
02237             }
02238             break;
02239         };
02240     }
02241     //---------------------------------------------------------------------
02242     void D3D9RenderSystem::setClipPlanes(const PlaneList& clipPlanes)
02243     {
02244         size_t i;
02245         size_t numClipPlanes;
02246         float dx9ClipPlane[4];
02247         DWORD mask = 0;
02248         HRESULT hr;
02249 
02250         numClipPlanes = clipPlanes.size();
02251         for (i = 0; i < numClipPlanes; ++i)
02252         {
02253             const Plane& plane = clipPlanes[i];
02254 
02255             dx9ClipPlane[0] = plane.normal.x;
02256             dx9ClipPlane[1] = plane.normal.y;
02257             dx9ClipPlane[2] = plane.normal.z;
02258             dx9ClipPlane[3] = -plane.d;
02259 
02260             hr = mpD3DDevice->SetClipPlane(i, dx9ClipPlane);
02261             if (FAILED(hr))
02262             {
02263                 Except(hr, "Unable to set clip plane", 
02264                     "D3D9RenderSystem::setClipPlanes");
02265             }
02266 
02267             mask |= (1 << i);
02268         }
02269 
02270         hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask);
02271         if (FAILED(hr))
02272         {
02273             Except(hr, "Unable to set render state for clip planes", 
02274                 "D3D9RenderSystem::setClipPlanes");
02275         }
02276     }
02277     //---------------------------------------------------------------------
02278     void D3D9RenderSystem::setScissorTest(bool enabled, size_t left, size_t top, size_t right,
02279         size_t bottom)
02280     {
02281         HRESULT hr;
02282         if (enabled)
02283         {
02284             if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE)))
02285             {
02286                 Except(hr, "Unable to enable scissor rendering state; " + getErrorDescription(hr), 
02287                     "D3D9RenderSystem::setScissorTest");
02288             }
02289             RECT rect;
02290             rect.left = left;
02291             rect.top = top;
02292             rect.bottom = bottom;
02293             rect.right = right;
02294             if (FAILED(hr = mpD3DDevice->SetScissorRect(&rect)))
02295             {
02296                 Except(hr, "Unable to set scissor rectangle; " + getErrorDescription(hr), 
02297                     "D3D9RenderSystem::setScissorTest");
02298             }
02299         }
02300         else
02301         {
02302             if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE)))
02303             {
02304                 Except(hr, "Unable to disable scissor rendering state; " + getErrorDescription(hr), 
02305                     "D3D9RenderSystem::setScissorTest");
02306             }
02307         }
02308     }
02309     //---------------------------------------------------------------------
02310     void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers, 
02311         const ColourValue& colour, Real depth, unsigned short stencil)
02312     {
02313         DWORD flags = 0;
02314         if (buffers & FBT_COLOUR)
02315         {
02316             flags |= D3DCLEAR_TARGET;
02317         }
02318         if (buffers & FBT_DEPTH)
02319         {
02320             flags |= D3DCLEAR_ZBUFFER;
02321         }
02322         // Only try to clear the stencil buffer if supported
02323         if (buffers & FBT_STENCIL && mCapabilities->hasCapability(RSC_HWSTENCIL))
02324         {
02325             flags |= D3DCLEAR_STENCIL;
02326         }
02327         HRESULT hr;
02328         if( FAILED( hr = mpD3DDevice->Clear( 
02329             0, 
02330             NULL, 
02331             flags,
02332             colour.getAsLongARGB(), 
02333             depth, 
02334             stencil ) ) )
02335         {
02336             String msg = DXGetErrorDescription9(hr);
02337             Except( hr, "Error clearing frame buffer : " 
02338                 + msg, "D3D9RenderSystem::clearFrameBuffer" );
02339         }
02340     }
02341     //---------------------------------------------------------------------
02342     void D3D9RenderSystem::_makeProjectionMatrix(Real left, Real right, 
02343         Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest,
02344         bool forGpuProgram)
02345     {
02346         Real width = right - left;
02347         Real height = top - bottom;
02348         Real q, qn;
02349         if (farPlane == 0)
02350         {
02351             q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
02352             qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
02353         }
02354         else
02355         {
02356             q = farPlane / ( farPlane - nearPlane );
02357             qn = -q * nearPlane;
02358         }
02359         dest = Matrix4::ZERO;
02360         dest[0][0] = 2 * nearPlane / width;
02361         dest[0][2] = (right+left) / width;
02362         dest[1][1] = 2 * nearPlane / height;
02363         dest[1][2] = (top+bottom) / height;
02364         if (forGpuProgram)
02365         {
02366             dest[2][2] = -q;
02367             dest[3][2] = -1.0f;
02368         }
02369         else
02370         {
02371             dest[2][2] = q;
02372             dest[3][2] = 1.0f;
02373         }
02374         dest[2][3] = qn;
02375     }
02376 
02377     // ------------------------------------------------------------------
02378     void D3D9RenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D)
02379     {
02380         float plane[4] = { A, B, C, D };
02381         mpD3DDevice->SetClipPlane (index, plane);
02382     }
02383 
02384     // ------------------------------------------------------------------
02385     void D3D9RenderSystem::enableClipPlane (ushort index, bool enable)
02386     {
02387         DWORD prev;
02388         mpD3DDevice->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev);
02389         __SetRenderState(D3DRS_CLIPPLANEENABLE, prev | (1 << index));
02390     }
02391     //---------------------------------------------------------------------
02392     HardwareOcclusionQuery* D3D9RenderSystem::createHardwareOcclusionQuery(void)
02393     {
02394         return new D3D9HardwareOcclusionQuery(mpD3DDevice); 
02395     }
02396     //---------------------------------------------------------------------
02397     Real D3D9RenderSystem::getHorizontalTexelOffset(void)
02398     {
02399         // D3D considers the origin to be in the center of a pixel
02400         return -0.5f;
02401     }
02402     //---------------------------------------------------------------------
02403     Real D3D9RenderSystem::getVerticalTexelOffset(void)
02404     {
02405         // D3D considers the origin to be in the center of a pixel
02406         return -0.5f;
02407     }
02408     //---------------------------------------------------------------------
02409     void D3D9RenderSystem::_applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane, 
02410         bool forGpuProgram)
02411     {
02412         // Thanks to Eric Lenyel for posting this calculation at www.terathon.com
02413 
02414         // Calculate the clip-space corner point opposite the clipping plane
02415         // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
02416         // transform it into camera space by multiplying it
02417         // by the inverse of the projection matrix
02418 
02419         /* generalised version
02420         Vector4 q = matrix.inverse() * 
02421             Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f);
02422         */
02423         Vector4 q;
02424         q.x = Math::Sign(plane.normal.x) / matrix[0][0];
02425         q.y = Math::Sign(plane.normal.y) / matrix[1][1];
02426         q.z = 1.0F; 
02427         // flip the next bit from Lengyel since we're right-handed
02428         if (forGpuProgram)
02429         {
02430             q.w = (1.0F - matrix[2][2]) / matrix[2][3];
02431         }
02432         else
02433         {
02434             q.w = (1.0F + matrix[2][2]) / matrix[2][3];
02435         }
02436 
02437         // Calculate the scaled plane vector
02438         Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
02439         Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q)));
02440 
02441         // Replace the third row of the projection matrix
02442         matrix[2][0] = c.x;
02443         matrix[2][1] = c.y;
02444         // flip the next bit from Lengyel since we're right-handed
02445         if (forGpuProgram)
02446         {
02447             matrix[2][2] = c.z; 
02448         }
02449         else
02450         {
02451             matrix[2][2] = -c.z; 
02452         }
02453         matrix[2][3] = c.w;        
02454     }
02455     //---------------------------------------------------------------------
02456     Real D3D9RenderSystem::getMinimumDepthInputValue(void)
02457     {
02458         // Range [0.0f, 1.0f]
02459         return 0.0f;
02460     }
02461     //---------------------------------------------------------------------
02462     Real D3D9RenderSystem::getMaximumDepthInputValue(void)
02463     {
02464         // Range [0.0f, 1.0f]
02465         // D3D inverts even identity view matrices, so maximum INPUT is -1.0
02466         return -1.0f;
02467     }
02468 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:21 2004