source: OGRE/trunk/ogrenew/RenderSystems/Direct3D7/src/OgreD3D7RenderSystem.cpp @ 657

Revision 657, 114.1 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://ogre.sourceforge.net/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include <malloc.h>
26#include "OgreD3D7RenderSystem.h"
27#include "OgreDDDriver.h"
28#include "OgreD3D7Device.h"
29#include "OgreD3D7DeviceList.h"
30#include "OgreDDDriverList.h"
31#include "OgreDDVideoModeList.h"
32#include "OgreDDVideoMode.h"
33#include "OgreRenderWindow.h"
34#include "OgreLogManager.h"
35#include "OgreRenderSystem.h"
36#include "OgreException.h"
37#include "OgreSceneManager.h"
38#include "OgreD3D7TextureManager.h"
39#include "OgreViewport.h"
40#include "OgreLight.h"
41#include "OgreMatrix4.h"
42#include "OgreMath.h"
43#include "OgreD3D7RenderWindow.h"
44#include "OgreFrustum.h"
45#include "OgreD3D7GpuProgramManager.h"
46#include "OgreStringConverter.h"
47
48namespace Ogre {
49    const Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE(
50        0.5,    0,  0, -0.5,
51          0, -0.5,  0, -0.5,
52          0,    0,  0,   -1,
53          0,    0,  0,    1);
54
55    const Matrix4 PROJECTIONCLIPSPACE2DTOIMAGESPACE_ORTHO(
56        -0.5,   0,  0, -0.5,
57           0, 0.5,  0, -0.5,
58           0,   0,  0,   -1,
59           0,   0,  0,    1);
60
61    //-----------------------------------------------------------------------
62    D3DRenderSystem::D3DRenderSystem(HINSTANCE hInstance)
63    {
64        OgreGuard( "D3DRenderSystem::D3DRenderSystem" );
65
66        LogManager::getSingleton().logMessage(getName() + " created.");
67
68        mlpD3DDevice = NULL;
69        // Reset driver list
70        mDriverList = NULL;
71        mActiveDDDriver = NULL;
72        mhInstance = hInstance;
73        mHardwareBufferManager = NULL;
74        mGpuProgramManager = NULL;
75                mDeviceLost = false;
76
77        initConfigOptions();
78
79        // Initialise D3DX library
80        D3DXInitialize();
81
82        // set stages desc. to defaults
83        for (int n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++)
84        {
85            mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
86            mTexStageDesc[n].coordIndex = 0;
87            mTexStageDesc[n].texType = D3D_TEX_TYPE_NORMAL;
88            mTexStageDesc[n].pTex = NULL;
89        }
90
91        mCurrentLights = 0;
92
93                mEventNames.push_back("DeviceLost");
94                mEventNames.push_back("DeviceRestored");
95
96        OgreUnguard();
97    }
98
99    //-----------------------------------------------------------------------
100    D3DRenderSystem::~D3DRenderSystem()
101    {
102        OgreGuard( "D3DRenderSystem::~D3DRenderSystem" );
103        shutdown();
104
105        SAFE_DELETE(mTextureManager);
106        SAFE_DELETE(mDriverList);
107        SAFE_DELETE(mHardwareBufferManager);
108        SAFE_DELETE(mGpuProgramManager);
109
110        D3DXUninitialize();
111        LogManager::getSingleton().logMessage(getName() + " destroyed.");
112
113        OgreUnguard();
114    }
115
116    //-----------------------------------------------------------------------
117    const String& D3DRenderSystem::getName(void) const
118    {
119        static String strName("Direct3D7 Rendering Subsystem");
120        return strName;
121    }
122
123    //-----------------------------------------------------------------------
124    void D3DRenderSystem::initConfigOptions(void)
125    {
126        OgreGuard( "D3DRenderSystem::initConfigOptions" );
127
128        DDDriverList* ddList;
129        DDDriver* dd;
130
131        ConfigOption optDevice;
132        ConfigOption optVideoMode;
133        ConfigOption optFullScreen;
134        ConfigOption optVSync;
135
136        ddList = this->getDirectDrawDrivers();
137
138        // Create option for devices
139        optDevice.name = "Rendering Device";
140        optDevice.currentValue = "";
141        optDevice.possibleValues.clear();
142        optDevice.immutable = false;
143
144        // Option for video modes
145        optVideoMode.name = "Video Mode";
146        optVideoMode.currentValue = "";
147        optVideoMode.immutable = false;
148
149        // Option for full screen
150        optFullScreen.name = "Full Screen";
151        optFullScreen.possibleValues.push_back("Yes");
152        optFullScreen.possibleValues.push_back("No");
153        optFullScreen.currentValue = "Yes";
154
155
156        unsigned k = ddList->count();
157        // First, get DirectDraw driver options
158        for( unsigned j = 0; j < ddList->count(); j++ )
159        {
160            dd = ddList->item(j);
161            // Add to device option list
162            optDevice.possibleValues.push_back( dd->DriverDescription() );
163
164            // Make first one default
165            if( j==0 )
166            {
167                optDevice.currentValue = dd->DriverDescription();
168
169            }
170
171
172        }
173
174        // VSync option
175        optVSync.name = "VSync";
176        optVSync.immutable = false;
177        optVSync.possibleValues.push_back("Yes");
178        optVSync.possibleValues.push_back("No");
179        optVSync.currentValue = "Yes";
180
181
182        mOptions[optDevice.name] = optDevice;
183        mOptions[optVideoMode.name] = optVideoMode;
184        mOptions[optFullScreen.name] = optFullScreen;
185        mOptions[optVSync.name] = optVSync;
186
187        // Set default-based settings
188        refreshDDSettings();
189
190        OgreUnguard();
191    }
192
193    //-----------------------------------------------------------------------
194    void D3DRenderSystem::refreshDDSettings(void)
195    {
196        OgreGuard( "D3DRenderSystem::refreshDDSettings" );
197
198        DDVideoMode* vid;
199        ConfigOption* optVideoMode;
200        ConfigOption* optFullScreen;
201        DDDriver* dd;
202
203        // Stuffs DD-Driver specific settings
204
205        // Find DD Driver selected in options
206        ConfigOptionMap::iterator opt = mOptions.find("Rendering Device");
207
208        if( opt != mOptions.end() )
209        {
210            for( unsigned j = 0; j < getDirectDrawDrivers()->count(); j++ )
211            {
212                dd = getDirectDrawDrivers()->item(j);
213                if( dd->DriverDescription() == opt->second.currentValue )
214                    break;
215            }
216
217            // Get fullScreen and Video mode options
218            opt = mOptions.find("Video Mode");
219            optVideoMode = &opt->second;
220            opt = mOptions.find("Full Screen");
221            optFullScreen = &opt->second;
222
223            // Full screen forced?
224            if (!(dd->CanRenderWindowed()))
225            {
226                setConfigOption("Full Screen", "Yes");
227                optFullScreen->immutable = true;
228            }
229            else
230                optFullScreen->immutable = false;
231
232            // Get video modes for this device
233            optVideoMode->possibleValues.clear();
234
235            for( unsigned k = 0; k<dd->getVideoModeList()->count(); k++ )
236            {
237                vid = dd->getVideoModeList()->item(k);
238                optVideoMode->possibleValues.push_back(vid->Description());
239            }
240        }
241
242        OgreUnguard();
243    }
244
245
246    //-----------------------------------------------------------------------
247    ConfigOptionMap& D3DRenderSystem::getConfigOptions(void)
248    {
249        // Return a COPY of the current config options
250        return mOptions;
251
252    }
253
254    //-----------------------------------------------------------------------
255    void D3DRenderSystem::setConfigOption(const String &name, const String &value)
256    {
257        OgreGuard( "D3DRenderSystem::setConfigOption" );
258
259        StringUtil::StrStreamType str;
260        str << "RenderSystem Option: " << name << " = " << value;
261        LogManager::getSingleton().logMessage(str.str());
262
263        // Find option
264        ConfigOptionMap::iterator it = mOptions.find(name);
265
266        // Update
267        if( it != mOptions.end())
268            it->second.currentValue = value;
269        else
270        {
271            str.clear();
272            str << "Option named " << name << " does not exist.";
273            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
274                str.str(), "D3DRenderSystem::setConfigOption");
275        }
276
277        // Refresh other options if DD Driver changed
278        if (name == "Rendering Device")
279            refreshDDSettings();
280
281        if (name == "Full Screen")
282        {
283            if (value == "No")
284            {
285                // Video mode is not applicable
286                it = mOptions.find("Video Mode");
287                it->second.currentValue = "N/A";
288                it->second.immutable = true;
289            }
290            else
291            {
292                // Video mode is applicable
293                it = mOptions.find("Video Mode");
294                // default to 640 x 480 x 16
295                it->second.currentValue = "640 x 480 @ 16-bit colour";
296                it->second.immutable = false;
297            }
298        }
299                if( name == "VSync" )
300                {
301                        if (value == "Yes")
302                                mVSync = true;
303                        else
304                                mVSync = false;
305                }
306
307        OgreUnguard();
308    }
309    //-----------------------------------------------------------------------
310    String D3DRenderSystem::validateConfigOptions(void)
311    {
312        // Check video mode specified in full screen mode
313        ConfigOptionMap::iterator o = mOptions.find("Full Screen");
314        if (o->second.currentValue == "Yes")
315        {
316            // Check video mode
317            o = mOptions.find("Video Mode");
318            if (o->second.currentValue == "")
319            {
320                return "A video mode must be selected for running in full-screen mode.";
321            }
322        }
323
324        o = mOptions.find( "Rendering Device" );
325        bool foundDriver = false;
326        DDDriverList* driverList = getDirectDrawDrivers();
327        for( ushort j=0; j < driverList->count(); j++ )
328        {
329            if( driverList->item(j)->DriverDescription() == o->second.currentValue )
330            {
331                foundDriver = true;
332                break;
333            }
334        }
335        if (!foundDriver)
336        {
337            // Just pick the first driver
338            setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
339            return "Your DirectX driver name has changed since the last time you ran OGRE; "
340                "the 'Rendering Device' has been changed.";
341        }
342        return "";
343
344    }
345    //-----------------------------------------------------------------------
346    RenderWindow* D3DRenderSystem::initialise(bool autoCreateWindow, const String& windowTitle)
347    {
348        RenderWindow* autoWindow = 0;
349
350
351        LogManager::getSingleton().logMessage(
352            "***************************************\n"
353            "*** Direct3D Subsystem Initialising ***\n"
354            "***************************************" );
355
356        // ---------------------------
357        // Init using current settings
358        // ---------------------------
359
360        // DirectDraw driver
361        mActiveDDDriver = 0;
362        ConfigOptionMap::iterator opt = mOptions.find("Rendering Device");
363        for( unsigned j = 0; j<getDirectDrawDrivers()->count(); j++ )
364        {
365            if (getDirectDrawDrivers()->item(j)->DriverDescription() == opt->second.currentValue)
366            {
367                mActiveDDDriver = getDirectDrawDrivers()->item(j);
368                break;
369            }
370        }
371
372        if (!mActiveDDDriver)
373            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Problems finding requested DirectDraw driver!",
374            "D3DRenderSystem::initialise");
375
376
377        // Sort out the creation of a new window if required
378        if (autoCreateWindow)
379        {
380            // Full screen?
381            bool fullScreen;
382            opt = mOptions.find("Full Screen");
383            if( opt == mOptions.end() )
384                OGRE_EXCEPT(999, "Can't find full screen option!",
385                "D3DRenderSystem::initialise");
386            if (opt->second.currentValue == "Yes")
387                fullScreen = true;
388            else
389                fullScreen = false;
390
391            // Get video mode
392            DDVideoMode* vid;
393            unsigned int height, width, colourDepth;
394
395            vid = 0;
396            String temp;
397            if (fullScreen)
398            {
399                opt = mOptions.find("Video Mode");
400
401                for( unsigned j=0; j<mActiveDDDriver->getVideoModeList()->count(); j++ )
402                {
403                    temp = mActiveDDDriver->getVideoModeList()->item(j)->Description();
404                    if (temp == opt->second.currentValue)
405                    {
406                        vid = mActiveDDDriver->getVideoModeList()->item(j);
407                        break;
408                    }
409                }
410
411                if (!vid)
412                    OGRE_EXCEPT(9999, "Can't find requested video mode.",
413                    "D3DRenderSystem::initilise");
414                width = vid->mWidth;
415                height = vid->mHeight;
416                colourDepth = vid->mColourDepth;
417
418            }
419            else
420            {
421                // Notional height / width
422                width = 800;
423                height = 600;
424                colourDepth = 0; // colour depth based on desktop
425            }
426
427            // Create myself a window
428                        NameValuePairList params;
429                        params["colourDepth"] = StringConverter::toString(colourDepth);
430                        params["vsync"] = StringConverter::toString(mVSync);
431            autoWindow = this->createRenderWindow(windowTitle, width, height, fullScreen, &params);
432
433            // If we have 16bit depth buffer enable w-buffering.
434            assert( autoWindow );
435            if ( autoWindow->getColourDepth() == 16 )
436            {
437                mWBuffer = true;
438            }
439            else
440            {
441                mWBuffer = false;
442            }
443
444        }
445
446        opt = mOptions.find("VSync");
447        if (opt!=mOptions.end())
448        {
449            if (opt->second.currentValue == "Yes")
450            {
451                setWaitForVerticalBlank(true);
452            }
453            else
454            {
455                setWaitForVerticalBlank(false);
456            }
457        }
458
459
460        LogManager::getSingleton().logMessage("*****************************************");
461        LogManager::getSingleton().logMessage("*** Direct3D Subsystem Initialised Ok ***");
462        LogManager::getSingleton().logMessage("*****************************************");
463
464        // call superclass method
465        RenderSystem::initialise(autoCreateWindow);
466
467                // Create buffer manager
468        mHardwareBufferManager = new D3D7HardwareBufferManager();
469        // Create dummy gpu manager
470        mGpuProgramManager = new D3D7GpuProgramManager();
471
472
473        return autoWindow;
474
475    }
476
477    //-----------------------------------------------------------------------
478    void D3DRenderSystem::reinitialise(void)
479    {
480        this->shutdown();
481        this->initialise(true);
482    }
483
484
485    //-----------------------------------------------------------------------
486    void D3DRenderSystem::shutdown(void)
487    {
488        RenderSystem::shutdown();
489
490        // Cleanup
491        // Release all DirectX resources
492        //D3DTextr_InvalidateAllTextures();
493        if (mActiveDDDriver)
494        {
495            mActiveDDDriver->Cleanup();
496        }
497
498        // Delete system objects
499        SAFE_DELETE(mDriverList);
500
501        mActiveDDDriver = NULL;
502
503
504
505        // Write termination message
506        LogManager::getSingleton().logMessage("*-*-* Direct3D Subsystem shutting down cleanly.");
507
508
509    }
510
511    //-----------------------------------------------------------------------
512    void D3DRenderSystem::setAmbientLight(float r, float g, float b)
513    {
514        // Call D3D
515        D3DCOLOR col = D3DRGB(r,g,b);
516
517        HRESULT hr = __SetRenderState(D3DRENDERSTATE_AMBIENT, col);
518        if (FAILED(hr))
519            OGRE_EXCEPT(hr, "Error setting ambient light.", "D3DRenderSystem::setAmbientLight");
520    }
521
522    //-----------------------------------------------------------------------
523    void D3DRenderSystem::setShadingType(ShadeOptions so)
524    {
525        D3DSHADEMODE d3dMode;
526        switch(so)
527        {
528        case SO_FLAT:
529            d3dMode = D3DSHADE_FLAT;
530            break;
531        case SO_GOURAUD:
532            d3dMode = D3DSHADE_GOURAUD;
533            break;
534        case SO_PHONG:
535            d3dMode = D3DSHADE_PHONG;
536            break;
537
538        }
539
540        HRESULT hr = __SetRenderState(D3DRENDERSTATE_SHADEMODE, d3dMode);
541        if (FAILED(hr))
542            OGRE_EXCEPT(hr, "Error setting shading mode.", "D3DRenderSystem::setShadingType");
543
544    }
545
546
547    //-----------------------------------------------------------------------
548        RenderWindow* D3DRenderSystem::createRenderWindow(const String &name,
549                unsigned int width, unsigned int height, bool fullScreen,
550                const NameValuePairList *miscParams)
551    {
552        static bool firstWindow = true;
553        OgreGuard( "D3DRenderSystem::createRenderWindow" );
554
555        String msg;
556
557        // Make sure we don't already have a render target of the
558        // same name as the one supplied
559        if( mRenderTargets.find( name ) != mRenderTargets.end() )
560        {
561            msg = msg + "A render target of the same name (" + name + ") already "
562                "exists. You cannot create a new window with this name.";
563            OGRE_EXCEPT(999,msg,"D3DRenderSystem::createRenderWindow");
564        }
565
566        RenderWindow* win = new D3D7RenderWindow(mhInstance, mActiveDDDriver);
567        // Create window, supplying DD interface & hInstance
568        win->create(name, width, height, fullScreen, miscParams);
569               
570        attachRenderTarget( *win );
571
572        // If this is the first window, get the D3D device
573        //  and create the texture manager, setup caps
574        if (firstWindow)
575        {
576            win->getCustomAttribute("D3DDEVICE", &mlpD3DDevice);
577            // Get caps
578            mlpD3DDevice->GetCaps(&mD3DDeviceDesc);
579            // Create my texture manager for use by others
580            // Note this is a Singleton; pointer is held static by superclass
581            mTextureManager = new D3DTextureManager(mlpD3DDevice);
582
583            // Check for hardware stencil support
584            // Get render target, then depth buffer and check format
585            LPDIRECTDRAWSURFACE7 lpTarget;
586            win->getCustomAttribute("DDBACKBUFFER", &lpTarget);
587            DDSCAPS2 ddscaps;
588            ZeroMemory(&ddscaps, sizeof(DDSCAPS2));
589            ddscaps.dwCaps = DDSCAPS_ZBUFFER;
590            lpTarget->GetAttachedSurface(&ddscaps, &lpTarget);
591            lpTarget->Release();
592            DDSURFACEDESC2 ddsd;
593            ddsd.dwSize = sizeof(DDSURFACEDESC2);
594            lpTarget->GetSurfaceDesc(&ddsd);
595            DWORD stencil =  ddsd.ddpfPixelFormat.dwStencilBitDepth;
596            if(stencil > 0)
597            {
598                mCapabilities->setCapability(RSC_HWSTENCIL);
599                mCapabilities->setStencilBufferBitDepth(stencil);
600                if ((mD3DDeviceDesc.dwStencilCaps & D3DSTENCILCAPS_INCR) &&
601                    (mD3DDeviceDesc.dwStencilCaps & D3DSTENCILCAPS_DECR))
602                    mCapabilities->setCapability(RSC_STENCIL_WRAP);
603            }
604
605            // Anisotropy?
606            if (mD3DDeviceDesc.dwMaxAnisotropy > 1)
607                mCapabilities->setCapability(RSC_ANISOTROPY);
608            // Blending between stages supported
609            mCapabilities->setCapability(RSC_BLENDING);
610            // Cubemapping
611            if (mD3DDeviceDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_CUBEMAP)
612                mCapabilities->setCapability(RSC_CUBEMAPPING);
613
614            // DOT3
615            if (mD3DDeviceDesc.dwTextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3)
616                mCapabilities->setCapability(RSC_DOT3);
617
618            // Set the number of texture units based on details from current device
619            mCapabilities->setNumTextureUnits(mD3DDeviceDesc.wMaxSimultaneousTextures);
620
621            Log* defaultLog = LogManager::getSingleton().getDefaultLog();
622                        if (defaultLog)
623                        {
624                                mCapabilities->log(defaultLog);
625                        }
626
627            firstWindow = false;
628        }
629
630        OgreUnguardRet( win );
631    }
632
633        RenderTexture * D3DRenderSystem::createRenderTexture( const String & name, unsigned int width, unsigned int height,
634                TextureType texType, PixelFormat internalFormat, const NameValuePairList *miscParams )
635    {
636        RenderTexture * rt = new D3D7RenderTexture( name, width, height, texType, internalFormat, miscParams );
637        attachRenderTarget( *rt );
638        return rt;
639    }
640
641    //-----------------------------------------------------------------------
642    // Low-level overridden members
643    //-----------------------------------------------------------------------
644        //---------------------------------------------------------------------
645    void D3DRenderSystem::_useLights(const LightList& lights, unsigned short limit)
646    {
647        LightList::const_iterator i, iend;
648        iend = lights.end();
649        unsigned short num = 0;
650        for (i = lights.begin(); i != iend && num < limit; ++i, ++num)
651        {
652            setD3DLight(num, *i);
653        }
654        // Disable extra lights
655        for (; num < mCurrentLights; ++num)
656        {
657            setD3DLight(num, NULL);
658        }
659        mCurrentLights = std::min(limit, static_cast<unsigned short>(lights.size()));
660
661    }
662    //-----------------------------------------------------------------------
663    void D3DRenderSystem::setD3DLight(size_t index, Light* lt)
664    {
665        // Add to D3D
666        HRESULT hr;
667        D3DLIGHT7 d3dLight;
668
669        if (!lt)
670        {
671            hr = mlpD3DDevice->LightEnable(index, FALSE);
672            if (FAILED(hr))
673                OGRE_EXCEPT(hr, "Unable to disable light.", "D3DRenderSystem::setD3DLight");
674        }
675        else
676        {
677            switch (lt->getType())
678            {
679            case Light::LT_POINT:
680                d3dLight.dltType = D3DLIGHT_POINT;
681                break;
682            case Light::LT_DIRECTIONAL:
683                d3dLight.dltType = D3DLIGHT_DIRECTIONAL;
684                break;
685            case Light::LT_SPOTLIGHT:
686                d3dLight.dltType = D3DLIGHT_SPOT;
687                d3dLight.dvFalloff = lt->getSpotlightFalloff();
688                d3dLight.dvTheta = lt->getSpotlightInnerAngle().valueRadians();
689                d3dLight.dvPhi = lt->getSpotlightOuterAngle().valueRadians();
690                break;
691            }
692
693            // Colours
694            ColourValue col;
695            col = lt->getDiffuseColour();
696            d3dLight.dcvDiffuse.r = col.r;
697            d3dLight.dcvDiffuse.g = col.g;
698            d3dLight.dcvDiffuse.b = col.b;
699            d3dLight.dcvDiffuse.a = col.a;
700
701            col = lt->getSpecularColour();
702            d3dLight.dcvSpecular.r = col.r;
703            d3dLight.dcvSpecular.g = col.g;
704            d3dLight.dcvSpecular.b = col.b;
705            d3dLight.dcvSpecular.a = col.a;
706
707            // Never use ambient for a movable light
708            d3dLight.dcvAmbient.r = 0.0;
709            d3dLight.dcvAmbient.g = 0.0;
710            d3dLight.dcvAmbient.b = 0.0;
711            d3dLight.dcvAmbient.a = 0.0;
712
713            // Position (Irrelevant for directional)
714            Vector3 vec;
715            if (lt->getType() != Light::LT_DIRECTIONAL)
716            {
717                vec = lt->getDerivedPosition();
718
719                d3dLight.dvPosition.x = vec.x;
720                d3dLight.dvPosition.y = vec.y;
721                d3dLight.dvPosition.z = vec.z;
722            }
723            // Direction (Irrelevant for point lights)
724            if (lt->getType() != Light::LT_POINT)
725            {
726                vec = lt->getDerivedDirection();
727                d3dLight.dvDirection.x = vec.x;
728                d3dLight.dvDirection.y = vec.y;
729                d3dLight.dvDirection.z = vec.z;
730            }
731            // Attenuation parameters
732            d3dLight.dvRange = lt->getAttenuationRange();
733            d3dLight.dvAttenuation0 = lt->getAttenuationConstant();
734            d3dLight.dvAttenuation1 = lt->getAttenuationLinear();
735            d3dLight.dvAttenuation2 = lt->getAttenuationQuadric();
736
737
738
739            // Set light state
740            hr = mlpD3DDevice->SetLight(index, &d3dLight);
741
742            if (FAILED(hr))
743                OGRE_EXCEPT(hr, "Unable to set light details", "D3DRenderSystem::setD3DLight");
744
745            hr = mlpD3DDevice->LightEnable(index, TRUE);
746            if (FAILED(hr))
747                OGRE_EXCEPT(hr, "Unable to enable light.", "D3DRenderSystem::setD3DLight");
748        }
749
750
751    }
752    //-----------------------------------------------------------------------
753    D3DMATRIX D3DRenderSystem::makeD3DMatrix(const Matrix4& mat)
754    {
755        // Transpose matrix
756        // D3D uses row vectors i.e. V*M
757        // Ogre, OpenGL and everything else uses coloumn vectors i.e. M*V
758        D3DMATRIX d3dMat;
759
760        d3dMat.m[0][0] = mat[0][0];
761        d3dMat.m[0][1] = mat[1][0];
762        d3dMat.m[0][2] = mat[2][0];
763        d3dMat.m[0][3] = mat[3][0];
764
765        d3dMat.m[1][0] = mat[0][1];
766        d3dMat.m[1][1] = mat[1][1];
767        d3dMat.m[1][2] = mat[2][1];
768        d3dMat.m[1][3] = mat[3][1];
769
770        d3dMat.m[2][0] = mat[0][2];
771        d3dMat.m[2][1] = mat[1][2];
772        d3dMat.m[2][2] = mat[2][2];
773        d3dMat.m[2][3] = mat[3][2];
774
775        d3dMat.m[3][0] = mat[0][3];
776        d3dMat.m[3][1] = mat[1][3];
777        d3dMat.m[3][2] = mat[2][3];
778        d3dMat.m[3][3] = mat[3][3];
779
780        return d3dMat;
781    }
782
783    Matrix4 D3DRenderSystem::convertD3DMatrix(const D3DMATRIX& d3dmat)
784    {
785        // The reverse of makeD3DMatrix
786        // Transpose matrix
787        // D3D uses row vectors i.e. V*M
788        // Ogre, OpenGL and everything else uses coloumn vectors i.e. M*V
789        Matrix4 mat;
790        for (unsigned row = 0; row < 4; ++row)
791            for (unsigned col = 0; col < 4; ++col)
792                mat[col][row] = d3dmat.m[row][col];
793
794        return mat;
795
796
797    }
798    //-----------------------------------------------------------------------
799    void D3DRenderSystem::_setWorldMatrix(const Matrix4 &m)
800    {
801        D3DMATRIX d3dmat;
802
803        d3dmat = makeD3DMatrix(m);
804
805        HRESULT hr = mlpD3DDevice->SetTransform(D3DTRANSFORMSTATE_WORLD, &d3dmat);
806
807        if (FAILED(hr))
808            OGRE_EXCEPT(hr, "Cannot set D3D world matrix",
809            "D3DRenderSystem::_setWorldMatrix");
810    }
811
812    //-----------------------------------------------------------------------
813    void D3DRenderSystem::_setViewMatrix(const Matrix4 &m)
814    {
815        // save latest view matrix
816        mViewMatrix = m;
817        mViewMatrix[2][0] = -mViewMatrix[2][0];
818        mViewMatrix[2][1] = -mViewMatrix[2][1];
819        mViewMatrix[2][2] = -mViewMatrix[2][2];
820        mViewMatrix[2][3] = -mViewMatrix[2][3];
821
822        D3DMATRIX d3dmat = makeD3DMatrix(mViewMatrix);
823
824        HRESULT hr = mlpD3DDevice->SetTransform(D3DTRANSFORMSTATE_VIEW, &d3dmat);
825
826        if (FAILED(hr))
827            OGRE_EXCEPT(hr, "Cannot set D3D view matrix",
828            "D3DRenderSystem::_setViewMatrix");
829
830    }
831    //-----------------------------------------------------------------------
832    void D3DRenderSystem::_setProjectionMatrix(const Matrix4 &m)
833    {
834        D3DMATRIX d3dmat = makeD3DMatrix(m);
835
836        if( mActiveRenderTarget->requiresTextureFlipping() )
837        {
838            d3dmat._22 = - d3dmat._22;
839        }
840
841        HRESULT hr = mlpD3DDevice->SetTransform(D3DTRANSFORMSTATE_PROJECTION, &d3dmat);
842
843        if (FAILED(hr))
844            OGRE_EXCEPT(hr, "Cannot set D3D projection matrix",
845            "D3DRenderSystem::_setProjectionMatrix");
846    }
847
848
849    //-----------------------------------------------------------------------
850    void D3DRenderSystem::_setSurfaceParams(const ColourValue &ambient,
851        const ColourValue &diffuse, const ColourValue &specular,
852        const ColourValue &emissive, const Real shininess,
853        TrackVertexColourType tracking)
854    {
855        // Remember last call
856        static ColourValue lastAmbient = ColourValue::Black;
857        static ColourValue lastDiffuse = ColourValue::Black;
858        static ColourValue lastSpecular = ColourValue::Black;
859        static ColourValue lastEmissive = ColourValue::Black;
860        static Real lastShininess = 0.0;
861        static TrackVertexColourType lastTracking = -1;
862
863        // Only update if changed
864        if (ambient != lastAmbient || diffuse != lastDiffuse ||
865            specular != lastSpecular || emissive != lastEmissive ||
866            shininess != lastShininess)
867        {
868            // Convert to D3D
869            D3DMATERIAL7 d3dMat;
870
871            d3dMat.dcvDiffuse.r = diffuse.r;
872            d3dMat.dcvDiffuse.g = diffuse.g;
873            d3dMat.dcvDiffuse.b = diffuse.b;
874            d3dMat.dcvDiffuse.a = diffuse.a;
875
876            d3dMat.dcvAmbient.r = ambient.r;
877            d3dMat.dcvAmbient.g = ambient.g;
878            d3dMat.dcvAmbient.b = ambient.b;
879            d3dMat.dcvAmbient.a = ambient.a;
880
881            d3dMat.dcvSpecular.r = specular.r;
882            d3dMat.dcvSpecular.g = specular.g;
883            d3dMat.dcvSpecular.b = specular.b;
884            d3dMat.dcvSpecular.a = specular.a;
885
886            d3dMat.dcvEmissive.r = emissive.r;
887            d3dMat.dcvEmissive.g = emissive.g;
888            d3dMat.dcvEmissive.b = emissive.b;
889            d3dMat.dcvEmissive.a = emissive.a;
890
891            d3dMat.dvPower = shininess;
892
893            HRESULT hr = mlpD3DDevice->SetMaterial(&d3dMat);
894            if (FAILED(hr))
895                OGRE_EXCEPT(hr, "Error setting D3D material.", "D3DRenderSystem::_setSurfaceParams");
896
897            // Remember the details
898            lastAmbient = ambient;
899            lastDiffuse = diffuse;
900            lastSpecular = specular;
901            lastEmissive = emissive;
902            lastShininess = shininess;               
903        }
904        if(tracking != lastTracking)
905        {
906            if(tracking != TVC_NONE)
907            {
908                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORVERTEX, TRUE);
909                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_AMBIENTMATERIALSOURCE, (tracking&TVC_AMBIENT)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
910                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_DIFFUSEMATERIALSOURCE, (tracking&TVC_DIFFUSE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
911                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_SPECULARMATERIALSOURCE, (tracking&TVC_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
912                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_EMISSIVEMATERIALSOURCE, (tracking&TVC_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
913            }
914            else
915            {
916                mlpD3DDevice->SetRenderState(D3DRENDERSTATE_COLORVERTEX, FALSE);               
917            }
918            lastTracking = tracking;
919        }
920    }
921    //-----------------------------------------------------------------------
922    void D3DRenderSystem::_setTexture(size_t stage, bool enabled, const String &texname)
923    {
924        HRESULT hr;
925        D3DTexturePtr dt = TextureManager::getSingleton().getByName(texname);
926        if (enabled && !dt.isNull())
927        {
928            // note used
929            dt->touch();
930
931            LPDIRECTDRAWSURFACE7 pTex = dt->getDDSurface();
932            if (pTex != mTexStageDesc[stage].pTex)
933            {
934                hr = mlpD3DDevice->SetTexture(stage, pTex );
935                if (FAILED(hr))
936                    OGRE_EXCEPT(hr, "Unable to set texture in D3D.", "D3DRenderSystem::_setTexture");
937
938                // set stage desc.
939                mTexStageDesc[stage].texType = _ogreTexTypeToD3DTexType(dt->getTextureType());
940                mTexStageDesc[stage].pTex = pTex;
941            }
942        }
943        else
944        {
945            hr = mlpD3DDevice->SetTexture(stage, 0);
946            if (FAILED(hr))
947                OGRE_EXCEPT(hr, "Unable to disable texture in D3D.", "D3DRenderSystem::_setTexture");
948            hr = __SetTextureStageState( stage, D3DTSS_COLOROP, D3DTOP_DISABLE );
949            if (FAILED(hr))
950                OGRE_EXCEPT(hr, "Unable to disable texture in D3D.", "D3DRenderSystem::_setTexture");
951
952            // set stage desc. to defaults
953            mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
954            mTexStageDesc[stage].coordIndex = 0;
955            mTexStageDesc[stage].texType = D3D_TEX_TYPE_NORMAL;
956            mTexStageDesc[stage].pTex = NULL;
957        }
958    }
959    //---------------------------------------------------------------------
960    DWORD getD3DTexCalc(TexCoordCalcMethod tcc)
961    {
962        switch (tcc)
963        {
964        case TEXCALC_NONE:
965            return 0;
966        case TEXCALC_ENVIRONMENT_MAP:
967            // D3D7 does not support spherical reflection
968            return D3DTSS_TCI_CAMERASPACENORMAL;
969        case TEXCALC_ENVIRONMENT_MAP_REFLECTION:
970            return D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR;
971        case TEXCALC_ENVIRONMENT_MAP_PLANAR:
972        case TEXCALC_PROJECTIVE_TEXTURE:
973            return D3DTSS_TCI_CAMERASPACEPOSITION;
974        case TEXCALC_ENVIRONMENT_MAP_NORMAL:
975            return D3DTSS_TCI_CAMERASPACENORMAL;
976        }
977    }
978    //-----------------------------------------------------------------------
979    void D3DRenderSystem::_setTextureCoordCalculation(size_t stage, TexCoordCalcMethod m,
980        const Frustum* frustum)
981    {
982        HRESULT hr = S_OK;
983        // record the stage state
984        mTexStageDesc[stage].autoTexCoordType = m;
985        mTexStageDesc[stage].frustum = frustum;
986
987        hr = __SetTextureStageState(stage, D3DTSS_TEXCOORDINDEX,
988            getD3DTexCalc(m) | mTexStageDesc[stage].coordIndex);
989        if( FAILED( hr ) )
990            OGRE_EXCEPT( hr, "Error setting texture coord calculation", "D3DRenderSystem::_setTextureCoordCalculation" );
991
992    }
993    //-----------------------------------------------------------------------
994    void D3DRenderSystem::_setTextureMatrix(size_t stage, const Matrix4& xForm)
995    {
996                HRESULT hr;
997                D3DMATRIX d3dMat; // the matrix we'll maybe apply
998                Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format
999       
1000
1001                /* If envmap is applied, since D3D7 doesn't support spheremap,
1002                then we have to use texture transform to make the camera space normal
1003                reference the envmap properly. This isn't exactly the same as spheremap
1004                (it looks nasty on flat areas because the camera space normals are the same)
1005                but it's the best approximation we have in the absence of a proper spheremap */
1006                if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_ENVIRONMENT_MAP)
1007                {
1008                        // concatenate with the xForm
1009            newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE);
1010                }
1011
1012        // If this is a cubic reflection, we need to modify using the view matrix
1013        if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION)
1014        {
1015            D3DMATRIX viewMatrix;
1016
1017            // Get view matrix
1018            mlpD3DDevice->GetTransform(D3DTRANSFORMSTATE_VIEW, &viewMatrix);
1019            // Get transposed 3x3, ie since D3D is transposed just copy
1020            // We want to transpose since that will invert an orthonormal matrix ie rotation
1021            Matrix4 ogreViewTransposed;
1022            ogreViewTransposed[0][0] = viewMatrix.m[0][0];
1023            ogreViewTransposed[0][1] = viewMatrix.m[0][1];
1024            ogreViewTransposed[0][2] = viewMatrix.m[0][2];
1025            ogreViewTransposed[0][3] = 0.0f;
1026
1027            ogreViewTransposed[1][0] = viewMatrix.m[1][0];
1028            ogreViewTransposed[1][1] = viewMatrix.m[1][1];
1029            ogreViewTransposed[1][2] = viewMatrix.m[1][2];
1030            ogreViewTransposed[1][3] = 0.0f;
1031
1032            ogreViewTransposed[2][0] = viewMatrix.m[2][0];
1033            ogreViewTransposed[2][1] = viewMatrix.m[2][1];
1034            ogreViewTransposed[2][2] = viewMatrix.m[2][2];
1035            ogreViewTransposed[2][3] = 0.0f;
1036
1037            ogreViewTransposed[3][0] = 0.0f;
1038            ogreViewTransposed[3][1] = 0.0f;
1039            ogreViewTransposed[3][2] = 0.0f;
1040            ogreViewTransposed[3][3] = 1.0f;
1041           
1042            newMat = newMat.concatenate(ogreViewTransposed);
1043        }
1044
1045        if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
1046        {
1047            // Derive camera space to projector space transform
1048            // To do this, we need to undo the camera view matrix, then
1049            // apply the projector view & projection matrices
1050            newMat = mViewMatrix.inverse();
1051            newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat;
1052            newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat;
1053            if (mTexStageDesc[stage].frustum->getProjectionType() == PT_PERSPECTIVE)
1054            {
1055                newMat = PROJECTIONCLIPSPACE2DTOIMAGESPACE_PERSPECTIVE * newMat;
1056            }
1057            else
1058            {
1059                newMat = PROJECTIONCLIPSPACE2DTOIMAGESPACE_ORTHO * newMat;
1060            }
1061            newMat = xForm * newMat;
1062
1063        }
1064
1065                // convert our matrix to D3D format
1066                d3dMat = makeD3DMatrix(newMat);
1067
1068                // need this if texture is a cube map, to invert D3D's z coord
1069                if (mTexStageDesc[stage].autoTexCoordType != TEXCALC_NONE &&
1070            mTexStageDesc[stage].autoTexCoordType != TEXCALC_PROJECTIVE_TEXTURE)
1071                {
1072                        d3dMat._13 = -d3dMat._13;
1073                        d3dMat._23 = -d3dMat._23;
1074                        d3dMat._33 = -d3dMat._33;
1075                        d3dMat._43 = -d3dMat._43;
1076                }
1077
1078                // set the matrix if it's not the identity
1079        if (!(newMat == Matrix4::IDENTITY))
1080                {
1081                        // tell D3D the dimension of tex. coord.
1082                        int texCoordDim;
1083            if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
1084            {
1085                texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3;
1086            }
1087            else
1088            {
1089                            switch (mTexStageDesc[stage].texType)
1090                            {
1091                            case D3D_TEX_TYPE_NORMAL:
1092                                    texCoordDim = D3DTTFF_COUNT2;
1093                                    break;
1094                            case D3D_TEX_TYPE_CUBE:
1095                            case D3D_TEX_TYPE_VOLUME:
1096                                    texCoordDim = D3DTTFF_COUNT3;
1097                            }
1098            }
1099
1100                        hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim );
1101                        if (FAILED(hr))
1102                                OGRE_EXCEPT( hr, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" );
1103
1104                        hr = mlpD3DDevice->SetTransform(
1105                (D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0 + stage), &d3dMat );
1106                        if (FAILED(hr))
1107                                OGRE_EXCEPT( hr, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
1108                }
1109                else
1110                {
1111                        // disable all of this
1112                        hr = __SetTextureStageState( stage, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
1113                        if( FAILED( hr ) )
1114                                OGRE_EXCEPT( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
1115
1116                        // set the identity matrix
1117                        D3DUtil_SetIdentityMatrix( d3dMat );
1118                        hr = mlpD3DDevice->SetTransform(
1119                (D3DTRANSFORMSTATETYPE)(D3DTRANSFORMSTATE_TEXTURE0 + stage), &d3dMat );
1120                        if( FAILED( hr ) )
1121                                OGRE_EXCEPT( hr, "Error setting texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
1122                }
1123    }
1124        //---------------------------------------------------------------------
1125        void D3DRenderSystem::_setTextureCoordSet( size_t stage, size_t index )
1126        {
1127                HRESULT hr;
1128                hr = __SetTextureStageState( stage, D3DTSS_TEXCOORDINDEX,
1129            getD3DTexCalc(mTexStageDesc[stage].autoTexCoordType) | index );
1130                if( FAILED( hr ) )
1131                        OGRE_EXCEPT( hr, "Unable to set texture coord. set index", "D3DRenderSystem::_setTextureCoordSet" );
1132        // Record settings
1133        mTexStageDesc[stage].coordIndex = index;
1134        }
1135    //-----------------------------------------------------------------------
1136    void D3DRenderSystem::_setTextureBlendMode(size_t stage, const LayerBlendModeEx& bm)
1137    {
1138        HRESULT hr;
1139        D3DTEXTURESTAGESTATETYPE tss;
1140        DWORD value;
1141
1142        if (bm.blendType == LBT_COLOUR)
1143        {
1144            tss = D3DTSS_COLOROP;
1145        }
1146        else if (bm.blendType == LBT_ALPHA)
1147        {
1148            tss= D3DTSS_ALPHAOP;
1149        }
1150
1151        switch (bm.operation)
1152        {
1153        case LBX_SOURCE1:
1154            value = D3DTOP_SELECTARG1;
1155            break;
1156        case LBX_SOURCE2:
1157            value = D3DTOP_SELECTARG2;
1158            break;
1159        case LBX_MODULATE:
1160            value = D3DTOP_MODULATE;
1161            break;
1162        case LBX_MODULATE_X2:
1163            value = D3DTOP_MODULATE2X;
1164            break;
1165        case LBX_MODULATE_X4:
1166            value = D3DTOP_MODULATE4X;
1167            break;
1168        case LBX_ADD:
1169            value = D3DTOP_ADD;
1170            break;
1171        case LBX_ADD_SIGNED:
1172            value = D3DTOP_ADDSIGNED;
1173            break;
1174        case LBX_ADD_SMOOTH:
1175            value = D3DTOP_ADDSMOOTH;
1176            break;
1177        case LBX_SUBTRACT:
1178            value = D3DTOP_SUBTRACT;
1179            break;
1180        case LBX_BLEND_DIFFUSE_ALPHA:
1181            value = D3DTOP_BLENDDIFFUSEALPHA;
1182            break;
1183        case LBX_BLEND_TEXTURE_ALPHA:
1184            value = D3DTOP_BLENDTEXTUREALPHA;
1185            break;
1186        case LBX_BLEND_CURRENT_ALPHA:
1187            value = D3DTOP_BLENDCURRENTALPHA;
1188            break;
1189        case LBX_BLEND_MANUAL:
1190            value = D3DTOP_BLENDFACTORALPHA;
1191            // Set factor in render state
1192            hr = __SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR,
1193                D3DRGBA(0,0,0,bm.factor));
1194            break;
1195        case LBX_DOTPRODUCT:
1196            if (mD3DDeviceDesc.dwTextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3)
1197                value = D3DTOP_DOTPRODUCT3;
1198            else
1199                value = D3DTOP_MODULATE;
1200            break;
1201        }
1202
1203        // Make call to set operation
1204        hr = __SetTextureStageState(stage, tss, value);
1205
1206        // Now set up sources
1207        D3DCOLOR manualD3D;
1208        if (bm.blendType == LBT_COLOUR)
1209        {
1210            tss = D3DTSS_COLORARG1;
1211            manualD3D = D3DRGBA(bm.colourArg1.r,bm.colourArg1.g,bm.colourArg1.b,1.0);
1212                        mManualBlendColours[stage][0] = bm.colourArg1;
1213        }
1214        else if (bm.blendType == LBT_ALPHA)
1215        {
1216            tss = D3DTSS_ALPHAARG1;
1217                        manualD3D = D3DRGBA(mManualBlendColours[stage][0].r,
1218                                mManualBlendColours[stage][0].g,
1219                                mManualBlendColours[stage][0].b,
1220                                bm.alphaArg1);
1221        }
1222        LayerBlendSource bs = bm.source1;
1223        for (int i = 0; i < 2; ++i)
1224        {
1225            switch (bs)
1226            {
1227            case LBS_CURRENT:
1228                value = D3DTA_CURRENT;
1229                break;
1230            case LBS_TEXTURE:
1231                value = D3DTA_TEXTURE;
1232                break;
1233            case LBS_DIFFUSE:
1234                value = D3DTA_DIFFUSE;
1235                break;
1236            case LBS_SPECULAR:
1237                value = D3DTA_SPECULAR;
1238                break;
1239            case LBS_MANUAL:
1240                value = D3DTA_TFACTOR;
1241                // Set factor in render state
1242                hr = __SetRenderState(D3DRENDERSTATE_TEXTUREFACTOR,    manualD3D);
1243                break;
1244            }
1245
1246            // Set source
1247            hr = __SetTextureStageState(stage, tss, value);
1248
1249            // Source2
1250            bs = bm.source2;
1251            if (bm.blendType == LBT_COLOUR)
1252            {
1253                tss = D3DTSS_COLORARG2;
1254                manualD3D = D3DRGBA(bm.colourArg2.r,bm.colourArg2.g,bm.colourArg2.b,1.0);
1255                                mManualBlendColours[stage][1] = bm.colourArg2;
1256            }
1257            else if (bm.blendType == LBT_ALPHA)
1258            {
1259                tss = D3DTSS_ALPHAARG2;
1260                                manualD3D = D3DRGBA(mManualBlendColours[stage][1].r,
1261                                        mManualBlendColours[stage][1].g,
1262                                        mManualBlendColours[stage][1].b
1263                                        ,bm.alphaArg2);
1264            }
1265        }
1266    }
1267    //-----------------------------------------------------------------------
1268    void D3DRenderSystem::_setTextureAddressingMode(size_t stage, TextureUnitState::TextureAddressingMode tam)
1269    {
1270        HRESULT hr;
1271        D3DTEXTUREADDRESS d3dType;
1272
1273        switch(tam)
1274        {
1275        case TextureUnitState::TAM_WRAP:
1276            d3dType = D3DTADDRESS_WRAP;
1277            break;
1278        case TextureUnitState::TAM_MIRROR:
1279            d3dType = D3DTADDRESS_MIRROR;
1280            break;
1281        case TextureUnitState::TAM_CLAMP:
1282            d3dType = D3DTADDRESS_CLAMP;
1283            break;
1284        }
1285
1286
1287        hr = __SetTextureStageState(stage, D3DTSS_ADDRESS, d3dType);
1288    }
1289    //-----------------------------------------------------------------------
1290    void D3DRenderSystem::_setSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor)
1291    {
1292        HRESULT hr;
1293        D3DBLEND d3dSrcBlend, d3dDestBlend;
1294
1295        D3DBLEND* pBlend = &d3dSrcBlend;
1296        SceneBlendFactor ogreBlend = sourceFactor;
1297
1298        for (int i = 0 ; i < 2; ++i)
1299        {
1300            switch(ogreBlend)
1301            {
1302            case SBF_ONE:
1303                *pBlend = D3DBLEND_ONE;
1304                break;
1305            case SBF_ZERO:
1306                *pBlend = D3DBLEND_ZERO;
1307                break;
1308            case SBF_DEST_COLOUR:
1309                *pBlend = D3DBLEND_DESTCOLOR;
1310                break;
1311            case SBF_SOURCE_COLOUR:
1312                *pBlend = D3DBLEND_SRCCOLOR;
1313                break;
1314            case SBF_ONE_MINUS_DEST_COLOUR:
1315                *pBlend = D3DBLEND_INVDESTCOLOR;
1316                break;
1317            case SBF_ONE_MINUS_SOURCE_COLOUR:
1318                *pBlend = D3DBLEND_INVSRCCOLOR;
1319                break;
1320            case SBF_DEST_ALPHA:
1321                *pBlend = D3DBLEND_DESTALPHA;
1322                break;
1323            case SBF_SOURCE_ALPHA:
1324                *pBlend = D3DBLEND_SRCALPHA;
1325                break;
1326            case SBF_ONE_MINUS_DEST_ALPHA:
1327                *pBlend = D3DBLEND_INVDESTALPHA;
1328                break;
1329            case SBF_ONE_MINUS_SOURCE_ALPHA:
1330                *pBlend = D3DBLEND_INVSRCALPHA;
1331                break;
1332            }
1333            ogreBlend = destFactor;
1334            pBlend = &d3dDestBlend;
1335
1336        }
1337
1338        hr = __SetRenderState(D3DRENDERSTATE_SRCBLEND, d3dSrcBlend);
1339
1340        hr = __SetRenderState(D3DRENDERSTATE_DESTBLEND, d3dDestBlend);
1341
1342        // Save last scene blend, because colour write off is simulated
1343        // through scene blend
1344        mSavedDestFactor = destFactor;
1345        mSavedSrcFactor = sourceFactor;
1346
1347
1348    }
1349    //-----------------------------------------------------------------------
1350    void D3DRenderSystem::_setAlphaRejectSettings(CompareFunction func, unsigned char value)
1351    {
1352        HRESULT hr;
1353        if (func != CMPF_ALWAYS_PASS)
1354        {
1355            if( FAILED( hr = __SetRenderState( D3DRENDERSTATE_ALPHATESTENABLE,  TRUE ) ) )
1356                OGRE_EXCEPT( hr, "Failed to enable alpha testing",
1357                "D3DRenderSystem::_setAlphaRejectSettings" );
1358        }
1359        else
1360        {
1361            if( FAILED( hr = __SetRenderState( D3DRENDERSTATE_ALPHATESTENABLE,  FALSE ) ) )
1362                OGRE_EXCEPT( hr, "Failed to disable alpha testing",
1363                "D3DRenderSystem::_setAlphaRejectSettings" );
1364        }
1365
1366        // Set always just be sure
1367        hr = __SetRenderState(D3DRENDERSTATE_ALPHAFUNC,
1368            convertCompareFunction(func));
1369
1370        hr = __SetRenderState(D3DRENDERSTATE_ALPHAREF, value);   
1371    }
1372    //-----------------------------------------------------------------------
1373    void D3DRenderSystem::_setViewport(Viewport *vp)
1374    {
1375                if (mDeviceLost)
1376                        return;
1377
1378        // Check if viewport is different
1379        if (vp != mActiveViewport || vp->_isUpdated())
1380        {
1381            mActiveViewport = vp;
1382            mActiveRenderTarget = vp->getTarget();
1383            // Ok, it's different. Time to set render target (maybe)
1384            //  and viewport params.
1385            D3DVIEWPORT7 d3dvp;
1386            HRESULT hr;
1387
1388            // Set render target
1389            // TODO - maybe only set when required?
1390            RenderTarget* target;
1391            target = vp->getTarget();
1392            // Get DD Back buffer
1393            LPDIRECTDRAWSURFACE7 pBack;
1394            target->getCustomAttribute("DDBACKBUFFER", &pBack);
1395                        if (pBack->IsLost())
1396                        {
1397                                _notifyDeviceLost();
1398                                return;
1399                        }
1400
1401            hr = mlpD3DDevice->SetRenderTarget( pBack, 0 );
1402
1403            _setCullingMode( mCullingMode );
1404
1405            // Set viewport dimensions
1406            d3dvp.dwX = vp->getActualLeft();
1407            d3dvp.dwY = vp->getActualTop();
1408            d3dvp.dwWidth = vp->getActualWidth();
1409            d3dvp.dwHeight = vp->getActualHeight();
1410
1411            // Z-values from 0.0 to 1.0 (TODO - standardise with OpenGL?)
1412            d3dvp.dvMinZ = 0.0f;
1413            d3dvp.dvMaxZ = 1.0f;
1414
1415            hr = mlpD3DDevice->SetViewport(&d3dvp);
1416
1417            if (FAILED(hr))
1418                OGRE_EXCEPT(hr, "Error setting D3D viewport.",
1419                "D3DRenderSystem::_setViewport");
1420
1421            vp->_clearUpdatedFlag();
1422
1423        }
1424    }
1425
1426    //-----------------------------------------------------------------------
1427    void D3DRenderSystem::_beginFrame(void)
1428    {
1429        OgreGuard( "D3DRenderSystem::_beginFrame" );
1430
1431        HRESULT hr;
1432
1433                // Device lost from somewhere outside?
1434                if (mDeviceLost)
1435                {
1436                        _restoreLostDevice();
1437                        if (mDeviceLost)
1438                                return; // try later
1439                }
1440
1441        if (!mActiveViewport)
1442            OGRE_EXCEPT(999, "Cannot begin frame - no viewport selected.",
1443            "D3DRenderSystem::_beginFrame");
1444
1445        // Clear the viewport if required
1446        if (mActiveViewport->getClearEveryFrame())
1447        {
1448            clearFrameBuffer(FBT_COLOUR | FBT_DEPTH,
1449                mActiveViewport->getBackgroundColour());
1450        }
1451
1452        hr = mlpD3DDevice->BeginScene();
1453        if (FAILED(hr))
1454                {
1455                        if (hr == DDERR_SURFACELOST || hr == DDERR_SURFACEBUSY)
1456                        {
1457                                _notifyDeviceLost();
1458                                _restoreLostDevice();
1459                                if (mDeviceLost)
1460                                        return; // try later
1461
1462                                if (FAILED(hr = mlpD3DDevice->BeginScene()))
1463                                        OGRE_EXCEPT(hr, "Error beginning frame after device restore: "
1464                                                + getErrorDescription(hr),
1465                                        "D3DRenderSystem::_beginFrame");
1466                        }
1467                        else
1468                        {
1469                                OGRE_EXCEPT(hr, "Error beginning frame: " + getErrorDescription(hr),
1470                                "D3DRenderSystem::_beginFrame");
1471                        }
1472                }
1473
1474        // Moved here from _render, no point checking every rendering call
1475        static bool firstTime = true;
1476        if (firstTime)
1477        {
1478            // First-time setup
1479            // Set up some defaults
1480
1481            // Allow alpha blending
1482            hr = __SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);
1483            if (FAILED(hr))
1484                OGRE_EXCEPT(hr, "Error enabling alpha blending option.",
1485                "D3DRenderSystem::_beginFrame");
1486
1487            // Allow specular effects
1488            hr = __SetRenderState(D3DRENDERSTATE_SPECULARENABLE, TRUE);
1489            if (FAILED(hr))
1490                OGRE_EXCEPT(hr, "Error enabling specular option.",
1491                "D3DRenderSystem::_beginFrame");
1492
1493            firstTime = false;
1494        }
1495
1496        OgreUnguard();
1497    }
1498
1499    //-----------------------------------------------------------------------
1500    void D3DRenderSystem::_render(const RenderOperation& op)
1501    {
1502        OgreGuard( "D3DRenderSystem::_render" );
1503        HRESULT hr;
1504
1505                if (mDeviceLost)
1506                        return;
1507
1508        // Exit immediately if there is nothing to render
1509                // Passing 0 arguments causes problems for Direct3D
1510        if (op.vertexData->vertexCount == 0 ||
1511                        (op.useIndexes && op.indexData->indexCount == 0))
1512            return;
1513
1514        // call superclass
1515        RenderSystem::_render(op);
1516        // Set up vertex flags
1517        DWORD d3dVertexFormat = 0;
1518        unsigned int numTexCoords = 0;
1519
1520        // Assume no more than 10 buffers!
1521        static unsigned char* pBufPtrs[10];
1522
1523        // Lock all the buffers first
1524        // They're system memory buffers anyway
1525        const VertexBufferBinding::VertexBufferBindingMap binds =
1526            op.vertexData->vertexBufferBinding->getBindings();
1527        VertexBufferBinding::VertexBufferBindingMap::const_iterator bindi, bindend;
1528        bindend = binds.end();
1529        for (bindi = binds.begin(); bindi != bindend; ++bindi)
1530        {
1531            // lock from vertex start only
1532            pBufPtrs[bindi->first] = static_cast<unsigned char*>(
1533                bindi->second->lock(
1534                    op.vertexData->vertexStart * bindi->second->getVertexSize(),
1535                    op.vertexData->vertexCount * bindi->second->getVertexSize(),
1536                    HardwareBuffer::HBL_READ_ONLY)
1537                    );
1538
1539        }
1540
1541        // Determine vertex format
1542
1543        // Struct for data pointers
1544        D3DDRAWPRIMITIVESTRIDEDDATA strideData;
1545
1546        // Iterate over elements
1547        VertexDeclaration::VertexElementList::const_iterator elemi, elemend;
1548        const VertexDeclaration::VertexElementList elems =
1549            op.vertexData->vertexDeclaration->getElements();
1550        elemend = elems.end();
1551        for (elemi = elems.begin(); elemi != elemend; ++elemi)
1552        {
1553            // Get a few basic details
1554            const VertexElement& elem = *elemi;
1555            unsigned short source = elem.getSource();
1556            size_t vertexSize = op.vertexData->vertexDeclaration->getVertexSize(source);
1557            size_t offset = elem.getOffset();
1558            // semantic-specific stuff
1559            switch (elem.getSemantic())
1560            {
1561            case VES_POSITION:
1562                d3dVertexFormat |= D3DFVF_XYZ; // Untransformed 
1563                strideData.position.lpvData = pBufPtrs[source] + offset;
1564                strideData.position.dwStride = static_cast<DWORD>(vertexSize);
1565                // Set up pointer
1566                break;
1567            case VES_NORMAL:
1568                d3dVertexFormat |= D3DFVF_NORMAL;
1569                strideData.normal.lpvData = pBufPtrs[source] + offset;
1570                strideData.normal.dwStride = static_cast<DWORD>(vertexSize);
1571                break;
1572            case VES_DIFFUSE:
1573                d3dVertexFormat |= D3DFVF_DIFFUSE;
1574                strideData.diffuse.lpvData = pBufPtrs[source] + offset;
1575                strideData.diffuse.dwStride = static_cast<DWORD>(vertexSize);
1576                break;
1577            case VES_SPECULAR:
1578                d3dVertexFormat |= D3DFVF_SPECULAR;
1579                strideData.specular.lpvData = pBufPtrs[source] + offset;
1580                strideData.specular.dwStride = static_cast<DWORD>(vertexSize);
1581                break;
1582            case VES_TEXTURE_COORDINATES:
1583                // texcoords must go in order
1584                if (elem.getIndex() != numTexCoords)
1585                {
1586                    OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Invalid vertex format, texture coordinates"
1587                        " must be in order wih no gaps.", "D3DRenderSystem::_render");
1588                }
1589                // Don't add D3DFVF_TEXn flag here, wait until we know how many total
1590                // However, specify size
1591                switch (elem.getType())
1592                {
1593                case VET_FLOAT1:
1594                    d3dVertexFormat |= D3DFVF_TEXCOORDSIZE1(numTexCoords);
1595                    break;
1596                case VET_FLOAT2:
1597                    d3dVertexFormat |= D3DFVF_TEXCOORDSIZE2(numTexCoords);
1598                    break;
1599                case VET_FLOAT3:
1600                    d3dVertexFormat |= D3DFVF_TEXCOORDSIZE3(numTexCoords);
1601                    break;
1602                case VET_FLOAT4:
1603                    d3dVertexFormat |= D3DFVF_TEXCOORDSIZE4(numTexCoords);
1604                    break;
1605                }
1606
1607                strideData.textureCoords[numTexCoords].lpvData = pBufPtrs[source] + offset;
1608                strideData.textureCoords[numTexCoords].dwStride = static_cast<DWORD>(vertexSize);
1609
1610                // Increment number of coords
1611                ++numTexCoords;
1612            }
1613
1614        }
1615        // Add combined texture flag
1616        switch(numTexCoords)
1617        {
1618            case 0:
1619                // do nothing
1620                break;
1621            case 1:
1622                d3dVertexFormat |= D3DFVF_TEX1;
1623                break;
1624            case 2:
1625                d3dVertexFormat |= D3DFVF_TEX2;
1626                break;
1627            case 3:
1628                d3dVertexFormat |= D3DFVF_TEX3;
1629                break;
1630            case 4:
1631                d3dVertexFormat |= D3DFVF_TEX4;
1632                break;
1633            case 5:
1634                d3dVertexFormat |= D3DFVF_TEX5;
1635                break;
1636            case 6:
1637                d3dVertexFormat |= D3DFVF_TEX6;
1638                break;
1639            case 7:
1640                d3dVertexFormat |= D3DFVF_TEX7;
1641                break;
1642            case 8:
1643                d3dVertexFormat |= D3DFVF_TEX8;
1644                break;
1645        }
1646
1647        // Determine rendering operation
1648        D3DPRIMITIVETYPE primType;
1649        switch (op.operationType)
1650        {
1651        case RenderOperation::OT_POINT_LIST:
1652            primType = D3DPT_POINTLIST;
1653            break;
1654        case RenderOperation::OT_LINE_LIST:
1655            primType = D3DPT_LINELIST;
1656            break;
1657        case RenderOperation::OT_LINE_STRIP:
1658            primType = D3DPT_LINESTRIP;
1659            break;
1660        case RenderOperation::OT_TRIANGLE_LIST:
1661            primType = D3DPT_TRIANGLELIST;
1662            break;
1663        case RenderOperation::OT_TRIANGLE_STRIP:
1664            primType = D3DPT_TRIANGLESTRIP;
1665            break;
1666        case RenderOperation::OT_TRIANGLE_FAN:
1667            primType = D3DPT_TRIANGLEFAN;
1668            break;
1669        }
1670
1671
1672        if (op.useIndexes)
1673        {
1674            // Get pointer to index buffer
1675            // D3D7 only allows 16-bit indexes, this is enforced in buffer manager
1676            unsigned short* pIdx = static_cast<unsigned short*>(
1677                op.indexData->indexBuffer->lock(
1678                    op.indexData->indexStart,
1679                    op.indexData->indexCount * sizeof(unsigned short),
1680                    HardwareBuffer::HBL_READ_ONLY) );
1681
1682            hr = mlpD3DDevice->DrawIndexedPrimitiveStrided(primType,
1683                d3dVertexFormat,
1684                &strideData,
1685                static_cast<DWORD>(op.vertexData->vertexCount),
1686                pIdx,
1687                static_cast<DWORD>(op.indexData->indexCount)
1688                , 0);
1689        }
1690        else
1691        {
1692            hr = mlpD3DDevice->DrawPrimitiveStrided(primType,
1693                d3dVertexFormat,
1694                &strideData,
1695                static_cast<DWORD>(op.vertexData->vertexCount),
1696                0);
1697        }
1698
1699        // unlock buffers
1700        for (bindi = binds.begin(); bindi != bindend; ++bindi)
1701        {
1702            bindi->second->unlock();
1703        }
1704
1705                // Ignore errors - lost device issues can occur late in RTTs
1706
1707
1708
1709        OgreUnguard();
1710    }
1711
1712    //-----------------------------------------------------------------------
1713    void D3DRenderSystem::_endFrame(void)
1714    {
1715        OgreGuard( "D3DRenderSystem::_endFrame" );
1716
1717                if (mDeviceLost)
1718                {
1719                        // Don't allow until next begin that restores
1720                        return;
1721                }
1722
1723        HRESULT hr;
1724        hr = mlpD3DDevice->EndScene();
1725
1726        if (FAILED(hr))
1727                {
1728                        if (hr == DDERR_SURFACELOST)
1729                        {
1730                                // Device lost
1731                                _notifyDeviceLost();
1732                        }
1733                        else
1734                        {
1735                                // ignore other errors, may not find out about device lost
1736                                // early enough in RTT situation
1737                        }
1738                }
1739
1740        OgreUnguard();
1741    }
1742        //-----------------------------------------------------------------------
1743        void D3DRenderSystem::_notifyDeviceLost(void)
1744        {
1745                LogManager::getSingleton().logMessage("!!! Direct3D Device Lost!");
1746                mDeviceLost = true;
1747
1748                fireEvent("DeviceLost");
1749        }
1750        //-----------------------------------------------------------------------
1751        void D3DRenderSystem::_restoreLostDevice(void)
1752        {
1753                HRESULT hr = mActiveDDDriver->directDraw()->TestCooperativeLevel();
1754                if (SUCCEEDED(hr))
1755                {
1756                        _restoreSurfaces();
1757                }
1758                else if (hr == DDERR_WRONGMODE)
1759                {
1760                         // display mode change
1761                        _recreateContext();
1762                }
1763                else if (hr == DDERR_EXCLUSIVEMODEALREADYSET)
1764                {
1765                        // This means that some app took exclusive mode access
1766                        // we need to sit in a loop till we get back to the right mode.
1767                        do
1768                        {
1769                                Sleep(1000);
1770                        }
1771                        while (DDERR_EXCLUSIVEMODEALREADYSET == (hr = mActiveDDDriver->directDraw()->TestCooperativeLevel()));
1772                        if (SUCCEEDED(hr))
1773                        {
1774                                // This means that the exclusive mode app relinquished its
1775                                // control and we are back to the safe mode, so simply restore.
1776                                _restoreSurfaces();
1777                        }
1778                        else if (hr == DDERR_WRONGMODE)
1779                        {
1780                                // This means that the exclusive mode app relinquished its
1781                                // control BUT we are back to some strange mode, so destroy
1782                                // and recreate.
1783                                _recreateContext();
1784                        }
1785                        else
1786                        {
1787                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1788                                        getErrorDescription(hr),
1789                                        "D3DRenderSystem::_restoreLostDevice");
1790                        }
1791                }
1792                else if (hr == DDERR_NOEXCLUSIVEMODE)
1793                {
1794                        // Not sure what to do here, it tends to fix itself after a few tries.
1795                        return;
1796                }
1797                else
1798                {
1799                        // Some other error has occurred which we haven't handled.
1800                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1801                                getErrorDescription(hr),
1802                                "D3DRenderSystem::_restoreLostDevice");
1803                }
1804
1805                LogManager::getSingleton().logMessage("!!! Direct3D Device successfully restored.");
1806                mDeviceLost = false;
1807                fireEvent("DeviceRestored");
1808        }
1809        //-----------------------------------------------------------------------------
1810        void D3DRenderSystem::_restoreSurfaces(void)
1811        {
1812                HRESULT hr = mActiveDDDriver->directDraw()->RestoreAllSurfaces();
1813                if (FAILED(hr))
1814                {
1815                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1816                                getErrorDescription(hr),
1817                                "D3DRenderSystem::_restoreLostDevice");
1818                }
1819
1820                // Need to reload all textures since surfaces are now blank
1821                static_cast<D3DTextureManager*>(mTextureManager)
1822                        ->reloadAfterLostDevice();
1823
1824        }
1825        //-----------------------------------------------------------------------------
1826        void D3DRenderSystem::_recreateContext(void)
1827        {
1828                // restore primary render window if fullscreen
1829                for (RenderTargetMap::iterator i = mRenderTargets.begin(); i != mRenderTargets.end(); ++i)
1830                {
1831                        RenderTarget* rt = i->second;
1832                        if (rt->isPrimary())
1833                        {
1834                                D3D7RenderWindow* d3dwin = static_cast<D3D7RenderWindow*>(rt);
1835                                d3dwin->releaseDDSurfaces();
1836                                d3dwin->createDDSurfaces();
1837                                d3dwin->createDepthBuffer();
1838                                break;
1839                        }
1840                }
1841        }
1842    //-----------------------------------------------------------------------
1843    void D3DRenderSystem::_setCullingMode(CullingMode mode)
1844    {
1845        HRESULT hr;
1846        DWORD d3dMode;
1847
1848        mCullingMode = mode;
1849
1850        if (mode == CULL_NONE)
1851        {
1852            d3dMode = D3DCULL_NONE;
1853        }
1854        else if( mode == CULL_CLOCKWISE )
1855        {
1856            if( (mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
1857                (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding))
1858                d3dMode = D3DCULL_CCW;
1859            else
1860                d3dMode = D3DCULL_CW;
1861        }
1862        else if (mode == CULL_ANTICLOCKWISE)
1863        {
1864            if( (mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
1865                (!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding))
1866                d3dMode = D3DCULL_CW;
1867            else
1868                d3dMode = D3DCULL_CCW;
1869        }
1870
1871        hr = __SetRenderState(D3DRENDERSTATE_CULLMODE, d3dMode);
1872        if (FAILED(hr))
1873            OGRE_EXCEPT(hr, "Unable to set D3D culling mode.",
1874            "D3DRenderSystem::_setCullingMode");
1875
1876    }
1877
1878    //-----------------------------------------------------------------------
1879    void D3DRenderSystem::_setDepthBufferParams(bool depthTest, bool depthWrite, CompareFunction depthFunction)
1880    {
1881        _setDepthBufferCheckEnabled(depthTest);
1882        _setDepthBufferWriteEnabled(depthWrite);
1883        _setDepthBufferFunction(depthFunction);
1884
1885    }
1886    //-----------------------------------------------------------------------
1887    void D3DRenderSystem::_setDepthBufferCheckEnabled(bool enabled)
1888    {
1889        HRESULT hr;
1890
1891        if (enabled)
1892        {
1893            // Use w-buffer if available and enabled
1894            if (mWBuffer && mD3DDeviceDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_WBUFFER)
1895                hr = __SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_USEW);
1896            else
1897                hr = __SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_TRUE);
1898            if (FAILED(hr))
1899                OGRE_EXCEPT(hr, "Error setting depth buffer test state.",
1900                "D3DRenderSystem::_setDepthBufferCheckEnabled");
1901        }
1902        else
1903        {
1904            hr = __SetRenderState(D3DRENDERSTATE_ZENABLE, D3DZB_FALSE);
1905            if (FAILED(hr))
1906                OGRE_EXCEPT(hr, "Error setting depth buffer test state.",
1907                "D3DRenderSystem::_setDepthBufferCheckEnabled");
1908        }
1909    }
1910    //-----------------------------------------------------------------------
1911    void D3DRenderSystem::_setDepthBufferWriteEnabled(bool enabled)
1912    {
1913        HRESULT hr;
1914
1915        hr = __SetRenderState(D3DRENDERSTATE_ZWRITEENABLE, enabled);
1916        if (FAILED(hr))
1917            OGRE_EXCEPT(hr, "Error setting depth buffer write state.",
1918            "D3DRenderSystem::_setDepthBufferWriteEnabled");
1919    }
1920    //-----------------------------------------------------------------------
1921    void D3DRenderSystem::_setDepthBufferFunction(CompareFunction func)
1922    {
1923        HRESULT hr = __SetRenderState(D3DRENDERSTATE_ZFUNC,
1924            convertCompareFunction(func));
1925        if (FAILED(hr))
1926            OGRE_EXCEPT(hr, "Error setting depth buffer test function.",
1927            "D3DRenderSystem::_setDepthBufferFunction");
1928    }
1929    //-----------------------------------------------------------------------
1930    void D3DRenderSystem::_setDepthBias(ushort bias)
1931    {
1932        HRESULT hr = __SetRenderState(D3DRENDERSTATE_ZBIAS,
1933            bias);
1934        if (FAILED(hr))
1935            OGRE_EXCEPT(hr, "Error setting depth bias.",
1936            "D3DRenderSystem::_setDepthBias");
1937    }
1938    //-----------------------------------------------------------------------
1939    String D3DRenderSystem::getErrorDescription(long errCode) const
1940    {
1941        char* errDesc;
1942        DWORD i;
1943
1944        errDesc = new char[255];
1945        // Try windows errors first
1946        i = FormatMessage(
1947            FORMAT_MESSAGE_FROM_HMODULE |
1948            FORMAT_MESSAGE_FROM_SYSTEM |
1949            FORMAT_MESSAGE_IGNORE_INSERTS,
1950            NULL,
1951            DDERR_SURFACELOST,
1952            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
1953            (LPTSTR) errDesc,
1954            255,
1955            NULL
1956            );
1957
1958
1959        if (i == 0)
1960        {
1961            // Not found in windows message descriptions
1962            switch (errCode)
1963            {
1964            case DD_OK:
1965                strcpy(errDesc, "DD_OK: The request completed successfully.");
1966                break;
1967            case DDERR_ALREADYINITIALIZED:
1968                strcpy(errDesc, "DDERR_ALREADYINITIALIZED: The object has already been initialized.");
1969                break;
1970            case DDERR_BLTFASTCANTCLIP :
1971                strcpy(errDesc, "DDERR_BLTFASTCANTCLIP: A DirectDrawClipper object is attached to a source surface that has passed into a call to the IDirectDrawSurface7::BltFast method.");
1972                break;
1973            case DDERR_CANNOTATTACHSURFACE:
1974                strcpy(errDesc, "DDERR_CANNOTATTACHSURFACE: A surface cannot be attached to another requested surface.");
1975                break;
1976            case DDERR_CANNOTDETACHSURFACE:
1977                strcpy(errDesc, "DDERR_CANNOTATTACHSURFACE: A surface cannot be detached from another requested surface.");
1978                break;
1979            case DDERR_CANTCREATEDC:
1980                strcpy(errDesc, "DDERR_CANTCREATEDC: Windows can not create any more device contexts (DCs), or a DC was requested for a palette-indexed surface when the surface had no palette and the display mode was not palette-indexed.");
1981                break;
1982            case DDERR_CANTDUPLICATE:
1983                strcpy(errDesc, "DDERR_CANTDUPLICATE: Primary and 3-D surfaces, or surfaces that are implicitly created, cannot be duplicated.");
1984                break;
1985            case DDERR_CANTLOCKSURFACE:
1986                strcpy(errDesc, "DDERR_CANTLOCKSURFACE: Access to this surface is refused because an attempt was made to lock the primary surface without DCI support.");
1987                break;
1988            case DDERR_CANTPAGELOCK:
1989                strcpy(errDesc, "DDERR_CANTPAGELOCK: An attempt to page lock a surface failed. Page lock will not work on a display-memory surface or an emulated primary surface.");
1990                break;
1991            case DDERR_CANTPAGEUNLOCK:
1992                strcpy(errDesc, "DDERR_CANTPAGEUNLOCK: An attempt to page unlock a surface failed. Page unlock will not work on a display-memory surface or an emulated primary surface.");
1993                break;
1994            case DDERR_CLIPPERISUSINGHWND:
1995                strcpy(errDesc, "DDERR_CLIPPERISUSINGHWND: An attempt was made to set a clip list for a DirectDrawClipper object that is already monitoring a window handle.");
1996                break;
1997            case DDERR_COLORKEYNOTSET:
1998                strcpy(errDesc, "DDERR_COLORKEYNOTSET: No source color key is specified for this operation.");
1999                break;
2000            case DDERR_CURRENTLYNOTAVAIL:
2001                strcpy(errDesc, "DDERR_CURRENTLYNOTAVAIL: No support is currently available.");
2002                break;
2003            case DDERR_DCALREADYCREATED:
2004                strcpy(errDesc, "DDERR_DCALREADYCREATED: A device context (DC) has already been returned for this surface. Only one DC can be retrieved for each surface.");
2005                break;
2006            case DDERR_DEVICEDOESNTOWNSURFACE:
2007                strcpy(errDesc, "DDERR_DEVICEDOESNTOWNSURFACE: Surfaces created by one DirectDraw device cannot be used directly by another DirectDraw device.");
2008                break;
2009            case DDERR_DIRECTDRAWALREADYCREATED:
2010                strcpy(errDesc, "DDERR_DIRECTDRAWALREADYCREATED: A DirectDraw object representing this driver has already been created for this process.");
2011                break;
2012            case DDERR_EXCEPTION:
2013                strcpy(errDesc, "DDERR_EXCEPTION: An exception was encountered while performing the requested operation.");
2014                break;
2015            case DDERR_EXCLUSIVEMODEALREADYSET:
2016                strcpy(errDesc, "DDERR_EXCLUSIVEMODEALREADYSET: An attempt was made to set the cooperative level when it was already set to exclusive.");
2017                break;
2018            case DDERR_EXPIRED:
2019                strcpy(errDesc, "DDERR_EXPIRED: The data has expired and is therefore no longer valid.");
2020                break;
2021            case DDERR_GENERIC:
2022                strcpy(errDesc, "DDERR_GENERIC: There is an undefined error condition.");
2023                break;
2024            case DDERR_HEIGHTALIGN:
2025                strcpy(errDesc, "DDERR_HEIGHTALIGN: The height of the provided rectangle is not a multiple of the required alignment.");
2026                break;
2027            case DDERR_HWNDALREADYSET:
2028                strcpy(errDesc, "DDERR_HWNDALREADYSET: The DirectDraw cooperative level window handle has already been set. It cannot be reset while the process has surfaces or palettes created.");
2029                break;
2030            case DDERR_HWNDSUBCLASSED:
2031                strcpy(errDesc, "DDERR_HWNDSUBCLASSED: DirectDraw is prevented from restoring state because the DirectDraw cooperative level window handle has been subclassed.");
2032                break;
2033            case DDERR_IMPLICITLYCREATED:
2034                strcpy(errDesc, "DDERR_IMPLICITLYCREATED: The surface cannot be restored because it is an implicitly created surface.");
2035                break;
2036            case DDERR_INCOMPATIBLEPRIMARY:
2037                strcpy(errDesc, "DDERR_INCOMPATIBLEPRIMARY: The primary surface creation request does not match with the existing primary surface.");
2038                break;
2039            case DDERR_INVALIDCAPS:
2040                strcpy(errDesc, "DDERR_INVALIDCAPS: One or more of the capability bits passed to the callback function are incorrect.");
2041                break;
2042            case DDERR_INVALIDCLIPLIST:
2043                strcpy(errDesc, "DDERR_INVALIDCLIPLIST: DirectDraw does not support the provided clip list.");
2044                break;
2045            case DDERR_INVALIDDIRECTDRAWGUID:
2046                strcpy(errDesc, "DDERR_INVALIDDIRECTDRAWGUID: The globally unique identifier (GUID) passed to the DirectDrawCreate function is not a valid DirectDraw driver identifier.");
2047                break;
2048            case DDERR_INVALIDMODE:
2049                strcpy(errDesc, "DDERR_INVALIDMODE: DirectDraw does not support the requested mode.");
2050                break;
2051            case DDERR_INVALIDOBJECT:
2052                strcpy(errDesc, "DDERR_INVALIDOBJECT: DirectDraw received a pointer that was an invalid DirectDraw object.");
2053                break;
2054            case DDERR_INVALIDPARAMS:
2055                strcpy(errDesc, "DDERR_INVALIDPARAMS: One or more of the parameters passed to the method are incorrect.");
2056                break;
2057            case DDERR_INVALIDPIXELFORMAT:
2058                strcpy(errDesc, "DDERR_INVALIDPIXELFORMAT: The pixel format was invalid as specified.");
2059                break;
2060            case DDERR_INVALIDPOSITION:
2061                strcpy(errDesc, "DDERR_INVALIDPOSITION: The position of the overlay on the destination is no longer legal.");
2062                break;
2063            case DDERR_INVALIDRECT:
2064                strcpy(errDesc, "DDERR_INVALIDRECT: The provided rectangle was invalid.");
2065                break;
2066            case DDERR_INVALIDSTREAM:
2067                strcpy(errDesc, "DDERR_INVALIDSTREAM: The specified stream contains invalid data.");
2068                break;
2069            case DDERR_INVALIDSURFACETYPE:
2070                strcpy(errDesc, "DDERR_INVALIDSURFACETYPE: The requested operation could not be performed because the surface was of the wrong type.");
2071                break;
2072            case DDERR_LOCKEDSURFACES:
2073                strcpy(errDesc, "DDERR_LOCKEDSURFACES: One or more surfaces are locked, causing the failure of the requested operation.");
2074                break;
2075            case DDERR_MOREDATA:
2076                strcpy(errDesc, "DDERR_MOREDATA: There is more data available than the specified buffer size can hold.");
2077                break;
2078            case DDERR_NO3D:
2079                strcpy(errDesc, "DDERR_NO3D: No 3-D hardware or emulation is present.");
2080                break;
2081            case DDERR_NOALPHAHW:
2082                strcpy(errDesc, "DDERR_NOALPHAHW: No alpha acceleration hardware is present or available, causing the failure of the requested operation.");
2083                break;
2084            case DDERR_NOBLTHW:
2085                strcpy(errDesc, "DDERR_NOBLTHW: No blitter hardware is present.");
2086                break;
2087            case DDERR_NOCLIPLIST:
2088                strcpy(errDesc, "DDERR_NOCLIPLIST: No clip list is available.");
2089                break;
2090            case DDERR_NOCLIPPERATTACHED:
2091                strcpy(errDesc, "DDERR_NOCLIPPERATTACHED: No DirectDrawClipper object is attached to the surface object.");
2092                break;
2093            case DDERR_NOCOLORCONVHW:
2094                strcpy(errDesc, "DDERR_NOCOLORCONVHW: The operation cannot be carried out because no color-conversion hardware is present or available.");
2095                break;
2096            case DDERR_NOCOLORKEY:
2097                strcpy(errDesc, "DDERR_NOCOLORKEY: The surface does not currently have a color key.");
2098                break;
2099            case DDERR_NOCOLORKEYHW:
2100                strcpy(errDesc, "DDERR_NOCOLORKEYHW: The operation cannot be carried out because there is no hardware support for the destination color key.");
2101                break;
2102            case DDERR_NOCOOPERATIVELEVELSET:
2103                strcpy(errDesc, "DDERR_NOCOOPERATIVELEVELSET: A create function is called without the IDirectDraw7::SetCooperativeLevel method being called.");
2104                break;
2105            case DDERR_NODC:
2106                strcpy(errDesc, "DDERR_NODC: No DC has ever been created for this surface.");
2107                break;
2108            case DDERR_NODDROPSHW:
2109                strcpy(errDesc, "DDERR_NODDROPSHW: No DirectDraw raster operation (ROP) hardware is available.");
2110                break;
2111            case DDERR_NODIRECTDRAWHW:
2112                strcpy(errDesc, "DDERR_NODIRECTDRAWHW: Hardware-only DirectDraw object creation is not possible; the driver does not support any hardware.");
2113                break;
2114            case DDERR_NODIRECTDRAWSUPPORT:
2115                strcpy(errDesc, "DDERR_NODIRECTDRAWSUPPORT: DirectDraw support is not possible with the current display driver.");
2116                break;
2117            case DDERR_NOEMULATION:
2118                strcpy(errDesc, "DDERR_NOEMULATION: Software emulation is not available.");
2119                break;
2120            case DDERR_NOEXCLUSIVEMODE:
2121                strcpy(errDesc, "DDERR_NOEXCLUSIVEMODE: The operation requires the application to have exclusive mode, but the application does not have exclusive mode.");
2122                break;
2123            case DDERR_NOFLIPHW:
2124                strcpy(errDesc, "DDERR_NOFLIPHW: Flipping visible surfaces is not supported.");
2125                break;
2126            case DDERR_NOFOCUSWINDOW:
2127                strcpy(errDesc, "DDERR_NOFOCUSWINDOW: An attempt was made to create or set a device window without first setting the focus window.");
2128                break;
2129            case DDERR_NOGDI:
2130                strcpy(errDesc, "DDERR_NOGDI: No GDI is present.");
2131                break;
2132            case DDERR_NOHWND:
2133                strcpy(errDesc, "DDERR_NOHWND: Clipper notification requires a window handle, or no window handle has been previously set as the cooperative level window handle.");
2134                break;
2135            case DDERR_NOMIPMAPHW:
2136                strcpy(errDesc, "DDERR_NOMIPMAPHW: The operation cannot be carried out because no mipmap capable texture mapping hardware is present or available.");
2137                break;
2138            case DDERR_NOMIRRORHW:
2139                strcpy(errDesc, "DDERR_NOMIRRORHW: The operation cannot be carried out because no mirroring hardware is present or available.");
2140                break;
2141            case DDERR_NONONLOCALVIDMEM:
2142                strcpy(errDesc, "DDERR_NONONLOCALVIDMEM: An attempt was made to allocate non-local video memory from a device that does not support non-local video memory.");
2143                break;
2144            case DDERR_NOOPTIMIZEHW:
2145                strcpy(errDesc, "DDERR_NOOPTIMIZEHW: The device does not support optimized surfaces.");
2146                break;
2147            case DDERR_NOOVERLAYDEST:
2148                strcpy(errDesc, "DDERR_NOOVERLAYDEST: The IDirectDrawSurface4::GetOverlayPosition method is called on an overlay that the IDirectDrawSurface7::UpdateOverlay method has not been called on to establish a destination.");
2149                break;
2150            case DDERR_NOOVERLAYHW:
2151                strcpy(errDesc, "DDERR_NOOVERLAYHW: The operation cannot be carried out because no overlay hardware is present or available.");
2152                break;
2153            case DDERR_NOPALETTEATTACHED:
2154                strcpy(errDesc, "DDERR_NOPALETTEATTACHED: No palette object is attached to this surface.");
2155                break;
2156            case DDERR_NOPALETTEHW:
2157                strcpy(errDesc, "DDERR_NOPALETTEHW: There is no hardware support for 16- or 256-color palettes.");
2158                break;
2159            case DDERR_NORASTEROPHW:
2160                strcpy(errDesc, "DDERR_NORASTEROPHW: The operation cannot be carried out because no appropriate raster operation hardware is present or available.");
2161                break;
2162            case DDERR_NOROTATIONHW:
2163                strcpy(errDesc, "DDERR_NOROTATIONHW: The operation cannot be carried out because no rotation hardware is present or available.");
2164                break;
2165            case DDERR_NOSTRETCHHW:
2166                strcpy(errDesc, "DDERR_NOSTRETCHHW: The operation cannot be carried out because there is no hardware support for stretching.");
2167                break;
2168            case DDERR_NOT4BITCOLOR:
2169                strcpy(errDesc, "DDERR_NOT4BITCOLOR: The DirectDrawSurface object is not using a 4-bit color palette and the requested operation requires a 4-bit color palette.");
2170                break;
2171            case DDERR_NOT4BITCOLORINDEX:
2172                strcpy(errDesc, "DDERR_NOT4BITCOLORINDEX: The DirectDrawSurface object is not using a 4-bit color index palette and the requested operation requires a 4-bit color index palette.");
2173                break;
2174            case DDERR_NOT8BITCOLOR:
2175                strcpy(errDesc, "DDERR_NOT8BITCOLOR: The DirectDrawSurface object is not using an 8-bit color palette and the requested operation requires an 8-bit color palette.");
2176                break;
2177            case DDERR_NOTAOVERLAYSURFACE:
2178                strcpy(errDesc, "DDERR_NOTAOVERLAYSURFACE: An overlay component is called for a non-overlay surface.");
2179                break;
2180            case DDERR_NOTEXTUREHW:
2181                strcpy(errDesc, "DDERR_NOTEXTUREHW: The operation cannot be carried out because no texture-mapping hardware is present or available.");
2182                break;
2183            case DDERR_NOTFLIPPABLE:
2184                strcpy(errDesc, "DDERR_NOTFLIPPABLE: An attempt has been made to flip a surface that cannot be flipped.");
2185                break;
2186            case DDERR_NOTFOUND:
2187                strcpy(errDesc, "DDERR_NOTFOUND: The requested item was not found.");
2188                break;
2189            case DDERR_NOTINITIALIZED:
2190                strcpy(errDesc, "DDERR_NOTINITIALIZED: An attempt was made to call an interface method of a DirectDraw object created by CoCreateInstance before the object was initialized.");
2191                break;
2192            case DDERR_NOTLOADED:
2193                strcpy(errDesc, "DDERR_NOTLOADED: The surface is an optimized surface, but it has not yet been allocated any memory.");
2194                break;
2195            case DDERR_NOTLOCKED:
2196                strcpy(errDesc, "DDERR_NOTLOCKED: An attempt is made to unlock a surface that was not locked.");
2197                break;
2198            case DDERR_NOTPAGELOCKED:
2199                strcpy(errDesc, "DDERR_NOTPAGELOCKED: An attempt is made to page unlock a surface with no outstanding page locks.");
2200                break;
2201            case DDERR_NOTPALETTIZED:
2202                strcpy(errDesc, "DDERR_NOTPALETTIZED: The surface being used is not a palette-based surface.");
2203                break;
2204            case DDERR_NOVSYNCHW:
2205                strcpy(errDesc, "DDERR_NOVSYNCHW: The operation cannot be carried out because there is no hardware support for vertical blank synchronized operations.");
2206                break;
2207            case DDERR_NOZBUFFERHW:
2208                strcpy(errDesc, "DDERR_NOZBUFFERHW: The operation to create a z-buffer in display memory or to perform a blit using a z-buffer cannot be carried out because there is no hardware support for z-buffers.");
2209                break;
2210            case DDERR_NOZOVERLAYHW:
2211                strcpy(errDesc, "DDERR_NOZOVERLAYHW: The overlay surfaces cannot be z-layered based on the z-order because the hardware does not support z-ordering of overlays.");
2212                break;
2213            case DDERR_OUTOFCAPS:
2214                strcpy(errDesc, "DDERR_OUTOFCAPS: The hardware needed for the requested operation has already been allocated.");
2215                break;
2216            case DDERR_OUTOFMEMORY:
2217                strcpy(errDesc, "DDERR_OUTOFMEMORY: DirectDraw does not have enough memory to perform the operation.");
2218                break;
2219            case DDERR_OUTOFVIDEOMEMORY:
2220                strcpy(errDesc, "DDERR_OUTOFVIDEOMEMORY: DirectDraw does not have enough display memory to perform the operation.");
2221                break;
2222            case DDERR_OVERLAPPINGRECTS:
2223                strcpy(errDesc, "DDERR_OVERLAPPINGRECTS: Operation could not be carried out because the source and destination rectangles are on the same surface and overlap each other.");
2224                break;
2225            case DDERR_OVERLAYCANTCLIP:
2226                strcpy(errDesc, "DDERR_OVERLAYCANTCLIP: The hardware does not support clipped overlays.");
2227                break;
2228            case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
2229                strcpy(errDesc, "DDERR_OVERLAYCOLORKEYONLYONEACTIVE: An attempt was made to have more than one color key active on an overlay.");
2230                break;
2231            case DDERR_OVERLAYNOTVISIBLE:
2232                strcpy(errDesc, "DDERR_OVERLAYNOTVISIBLE: The IDirectDrawSurface7::GetOverlayPosition method is called on a hidden overlay.");
2233                break;
2234            case DDERR_PALETTEBUSY:
2235                strcpy(errDesc, "DDERR_PALETTEBUSY: Access to this palette is refused because the palette is locked by another thread.");
2236                break;
2237            case DDERR_PRIMARYSURFACEALREADYEXISTS:
2238                strcpy(errDesc, "DDERR_PRIMARYSURFACEALREADYEXISTS: This process has already created a primary surface.");
2239                break;
2240            case DDERR_REGIONTOOSMALL:
2241                strcpy(errDesc, "DDERR_REGIONTOOSMALL: The region passed to the IDirectDrawClipper::GetClipList method is too small.");
2242                break;
2243            case DDERR_SURFACEALREADYATTACHED:
2244                strcpy(errDesc, "DDERR_SURFACEALREADYATTACHED: An attempt was made to attach a surface to another surface to which it is already attached.");
2245                break;
2246            case DDERR_SURFACEALREADYDEPENDENT:
2247                strcpy(errDesc, "DDERR_SURFACEALREADYDEPENDENT: An attempt was made to make a surface a dependency of another surface to which it is already dependent.");
2248                break;
2249            case DDERR_SURFACEBUSY:
2250                strcpy(errDesc, "DDERR_SURFACEBUSY: Access to the surface is refused because the surface is locked by another thread.");
2251                break;
2252            case DDERR_SURFACEISOBSCURED:
2253                strcpy(errDesc, "DDERR_SURFACEISOBSCURED: Access to the surface is refused because the surface is obscured.");
2254                break;
2255            case DDERR_SURFACELOST:
2256                strcpy(errDesc, "DDERR_SURFACELOST: Access to the surface is refused because the surface memory is gone. Call the IDirectDrawSurface7::Restore method on this surface to restore the memory associated with it.");
2257                break;
2258            case DDERR_SURFACENOTATTACHED:
2259                strcpy(errDesc, "DDERR_SURFACENOTATTACHED: The requested surface is not attached.");
2260                break;
2261            case DDERR_TOOBIGHEIGHT:
2262                strcpy(errDesc, "DDERR_TOOBIGHEIGHT: The height requested by DirectDraw is too large.");
2263                break;
2264            case DDERR_TOOBIGSIZE:
2265                strcpy(errDesc, "DDERR_TOOBIGSIZE: The size requested by DirectDraw is too large. However, the individual height and width are valid sizes.");
2266                break;
2267            case DDERR_TOOBIGWIDTH:
2268                strcpy(errDesc, "DDERR_TOOBIGWIDTH: The width requested by DirectDraw is too large.");
2269                break;
2270            case DDERR_UNSUPPORTED:
2271                strcpy(errDesc, "DDERR_UNSUPPORTED: The operation is not supported.");
2272                break;
2273            case DDERR_UNSUPPORTEDFORMAT:
2274                strcpy(errDesc, "DDERR_UNSUPPORTEDFORMAT: The FourCC format requested is not supported by DirectDraw.");
2275                break;
2276            case DDERR_UNSUPPORTEDMASK:
2277                strcpy(errDesc, "DDERR_UNSUPPORTEDMASK: The bitmask in the pixel format requested is not supported by DirectDraw.");
2278                break;
2279            case DDERR_UNSUPPORTEDMODE:
2280                strcpy(errDesc, "DDERR_UNSUPPORTEDMODE: The display is currently in an unsupported mode.");
2281                break;
2282            case DDERR_VERTICALBLANKINPROGRESS:
2283                strcpy(errDesc, "DDERR_VERTICALBLANKINPROGRESS: A vertical blank is in progress.");
2284                break;
2285            case DDERR_VIDEONOTACTIVE:
2286                strcpy(errDesc, "DDERR_VIDEONOTACTIVE: The video port is not active.");
2287                break;
2288            case DDERR_WASSTILLDRAWING:
2289                strcpy(errDesc, "DDERR_WASSTILLDRAWING: The previous blit operation that is transferring information to or from this surface is incomplete.");
2290                break;
2291            case DDERR_WRONGMODE:
2292                strcpy(errDesc, "DDERR_WRONGMODE: This surface cannot be restored because it was created in a different mode.");
2293                break;
2294            case DDERR_XALIGN:
2295                strcpy(errDesc, "DDERR_XALIGN: The provided rectangle was not horizontally aligned on a required boundary.");
2296                break;
2297            default:
2298                strcpy(errDesc, "Unknown error code.");
2299            }
2300        }
2301        return errDesc;
2302    }
2303
2304    /*
2305    D3D_OK
2306    D3DERR_BADMAJORVERSION
2307    D3DERR_BADMINORVERSION
2308    D3DERR_COLORKEYATTACHED
2309    D3DERR_CONFLICTINGTEXTUREFILTER
2310    D3DERR_CONFLICTINGTEXTUREPALETTE
2311    D3DERR_CONFLICTINGRENDERSTATE
2312    D3DERR_DEVICEAGGREGATED (new for DirectX 5.0)
2313    D3DERR_EXECUTE_CLIPPED_FAILED
2314    D3DERR_EXECUTE_CREATE_FAILED
2315    D3DERR_EXECUTE_DESTROY_FAILED
2316    D3DERR_EXECUTE_FAILED
2317    D3DERR_EXECUTE_LOCK_FAILED
2318    D3DERR_EXECUTE_LOCKED
2319    D3DERR_EXECUTE_NOT_LOCKED
2320    D3DERR_EXECUTE_UNLOCK_FAILED
2321    D3DERR_INITFAILED (new for DirectX 5.0)
2322    D3DERR_INBEGIN (new for DirectX 5.0)
2323    D3DERR_INVALID_DEVICE (new for DirectX 5.0)
2324    D3DERR_INVALIDCURRENTVIEWPORT (new for DirectX 5.0)
2325    D3DERR_INVALIDMATRIX
2326    D3DERR_INVALIDPALETTE(new for DirectX 5.0)
2327    D3DERR_INVALIDPRIMITIVETYPE (new for DirectX 5.0)
2328    D3DERR_INVALIDRAMPTEXTURE (new for DirectX 5.0)
2329    D3DERR_INVALIDVERTEXFORMAT (new for DirectX 6.0)
2330    D3DERR_INVALIDVERTEXTYPE (new for DirectX 5.0)
2331    D3DERR_LIGHT_SET_FAILED
2332    D3DERR_LIGHTHASVIEWPORT (new for DirectX 5.0)
2333    D3DERR_LIGHTNOTINTHISVIEWPORT (new for DirectX 5.0)
2334    D3DERR_MATERIAL_CREATE_FAILED
2335    D3DERR_MATERIAL_DESTROY_FAILED
2336    D3DERR_MATERIAL_GETDATA_FAILED
2337    D3DERR_MATERIAL_SETDATA_FAILED
2338    D3DERR_MATRIX_CREATE_FAILED
2339    D3DERR_MATRIX_DESTROY_FAILED
2340    D3DERR_MATRIX_GETDATA_FAILED
2341    D3DERR_MATRIX_SETDATA_FAILED
2342    D3DERR_NOCURRENTVIEWPORT (new for DirectX 5.0)
2343    D3DERR_NOTINBEGIN (new for DirectX 5.0)
2344    D3DERR_NOVIEWPORTS (new for DirectX 5.0)
2345    D3DERR_SCENE_BEGIN_FAILED
2346    D3DERR_SCENE_END_FAILED
2347    D3DERR_SCENE_IN_SCENE
2348    D3DERR_SCENE_NOT_IN_SCENE
2349    D3DERR_SETVIEWPORTDATA_FAILED
2350    D3DERR_STENCILBUFFER_NOTPRESENT
2351    D3DERR_SURFACENOTINVIDMEM (new for DirectX 5.0)
2352    D3DERR_TEXTURE_BADSIZE (new for DirectX 5.0)
2353    D3DERR_TEXTURE_CREATE_FAILED
2354    D3DERR_TEXTURE_DESTROY_FAILED
2355    D3DERR_TEXTURE_GETSURF_FAILED
2356    D3DERR_TEXTURE_LOAD_FAILED
2357    D3DERR_TEXTURE_LOCK_FAILED
2358    D3DERR_TEXTURE_LOCKED
2359    D3DERR_TEXTURE_NO_SUPPORT
2360    D3DERR_TEXTURE_NOT_LOCKED
2361    D3DERR_TEXTURE_SWAP_FAILED
2362    D3DERR_TEXTURE_UNLOCK_FAILED
2363    D3DERR_TOOMANYOPERATIONS
2364    D3DERR_TOOMANYPRIMITIVES
2365    D3DERR_UNSUPPORTEDALPHAARG
2366    D3DERR_UNSUPPORTEDALPHAOPERATION
2367    D3DERR_UNSUPPORTEDCOLORARG
2368    D3DERR_UNSUPPORTEDCOLOROPERATION
2369    D3DERR_UNSUPPORTEDFACTORVALUE
2370    D3DERR_UNSUPPORTEDTEXTUREFILTER
2371    D3DERR_VBUF_CREATE_FAILED
2372    D3DERR_VERTEXBUFFERLOCKED
2373    D3DERR_VERTEXBUFFEROPTIMIZED
2374    D3DERR_VIEWPORTDATANOTSET (new for DirectX 5.0)
2375    D3DERR_VIEWPORTHASNODEVICE (new for DirectX 5.0)
2376    D3DERR_WRONGTEXTUREFORMAT
2377    D3DERR_ZBUFF_NEEDS_SYSTEMMEMORY (new for DirectX 5.0)
2378    D3DERR_ZBUFF_NEEDS_VIDEOMEMORY (new for DirectX 5.0)
2379    D3DERR_ZBUFFER_NOTPRESENT
2380    */
2381
2382    //-----------------------------------------------------------------------
2383    DDDriverList* D3DRenderSystem::getDirectDrawDrivers(void)
2384    {
2385        if (!mDriverList)
2386        {
2387            mDriverList = new DDDriverList;
2388        }
2389
2390        return mDriverList;
2391    }
2392    //-----------------------------------------------------------------------
2393    void D3DRenderSystem::setLightingEnabled(bool enabled)
2394    {
2395        // Call D3D
2396        HRESULT hr = __SetRenderState(D3DRENDERSTATE_LIGHTING, enabled);
2397        if (FAILED(hr))
2398            OGRE_EXCEPT(hr, "Error lighting status.", "D3DRenderSystem::setLightingEnabled");
2399    }
2400    //-----------------------------------------------------------------------
2401    void D3DRenderSystem::_setFog(FogMode mode, const ColourValue& colour, Real density, Real start, Real end)
2402    {
2403        HRESULT hr;
2404
2405        D3DRENDERSTATETYPE fogType, fogTypeNot;
2406
2407        if (mD3DDeviceDesc.dpcTriCaps.dwRasterCaps & D3DPRASTERCAPS_FOGTABLE)
2408        {
2409            fogType = D3DRENDERSTATE_FOGTABLEMODE;
2410            fogTypeNot = D3DRENDERSTATE_FOGVERTEXMODE;
2411        }
2412        else
2413        {
2414            fogType = D3DRENDERSTATE_FOGVERTEXMODE;
2415            fogTypeNot = D3DRENDERSTATE_FOGTABLEMODE;
2416        }
2417
2418        if( mode == FOG_NONE)
2419        {
2420            // just disable
2421            hr = __SetRenderState(fogType, D3DFOG_NONE );
2422            hr = __SetRenderState(D3DRENDERSTATE_FOGENABLE, FALSE);
2423        }
2424        else
2425        {
2426            // Allow fog
2427            hr = __SetRenderState( D3DRENDERSTATE_FOGENABLE, TRUE );
2428            hr = __SetRenderState( fogTypeNot, D3DFOG_NONE );
2429            switch(mode)
2430            {
2431            case FOG_EXP:
2432                hr = __SetRenderState( fogType, D3DFOG_EXP);
2433                break;
2434            case FOG_EXP2:
2435                hr = __SetRenderState( fogType, D3DFOG_EXP2);
2436                break;
2437            case FOG_LINEAR:
2438                hr = __SetRenderState( fogType, D3DFOG_LINEAR);
2439                break;
2440
2441            }
2442
2443            hr = __SetRenderState( D3DRENDERSTATE_FOGCOLOR, colour.getAsARGB() );
2444            hr = __SetRenderState( D3DRENDERSTATE_FOGSTART, *((LPDWORD)(&start)) );
2445            hr = __SetRenderState( D3DRENDERSTATE_FOGEND, *((LPDWORD)(&end)) );
2446            hr = __SetRenderState( D3DRENDERSTATE_FOGDENSITY, *((LPDWORD)(&density)) );
2447        }
2448
2449
2450    }
2451
2452    //---------------------------------------------------------------------
2453    void D3DRenderSystem::convertColourValue(const ColourValue& colour, uint32* pDest)
2454    {
2455        *pDest = colour.getAsARGB();
2456    }
2457    //---------------------------------------------------------------------
2458    void D3DRenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect,
2459        Real nearPlane, Real farPlane, Matrix4& dest, bool forGpuProgram)
2460    {
2461        Radian theta(fovy * 0.5);
2462        Real h = 1 / Math::Tan(theta);
2463        Real w = h / aspect;
2464        Real q, qn;
2465        if (farPlane == 0)
2466        {
2467            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
2468            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
2469        }
2470        else
2471        {
2472            q = farPlane / ( farPlane - nearPlane );
2473            qn = -q * nearPlane;
2474        }
2475
2476        dest = Matrix4::ZERO;
2477        dest[0][0] = w;
2478        dest[1][1] = h;
2479
2480        if (forGpuProgram)
2481        {
2482            dest[2][2] = -q;
2483            dest[3][2] = -1.0f;
2484        }
2485        else
2486        {
2487            dest[2][2] = q;
2488            dest[3][2] = 1.0f;
2489        }
2490
2491        dest[2][3] = qn;
2492
2493    }
2494    //---------------------------------------------------------------------
2495    void D3DRenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane,
2496        Matrix4& dest, bool forGpuProgram )
2497    {
2498        Radian thetaY (fovy / 2.0f);
2499        Real tanThetaY = Math::Tan(thetaY);
2500
2501        //Real thetaX = thetaY * aspect;
2502        Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX);
2503        Real half_w = tanThetaX * nearPlane;
2504        Real half_h = tanThetaY * nearPlane;
2505        Real iw = 1.0 / half_w;
2506        Real ih = 1.0 / half_h;
2507        Real q;
2508        if (farPlane == 0)
2509        {
2510            q = 0;
2511        }
2512        else
2513        {
2514            q = 1.0 / (farPlane - nearPlane);
2515        }
2516
2517        dest = Matrix4::ZERO;
2518        dest[0][0] = iw;
2519        dest[1][1] = ih;
2520        dest[2][2] = q;
2521        dest[2][3] = -nearPlane / (farPlane - nearPlane);
2522        dest[3][3] = 1;
2523
2524        if (forGpuProgram)
2525        {
2526            dest[2][2] = -dest[2][2];
2527        }
2528    }
2529    //---------------------------------------------------------------------
2530    void D3DRenderSystem::_setRasterisationMode(SceneDetailLevel level)
2531    {
2532        D3DFILLMODE d3dmode;
2533
2534        switch(level)
2535        {
2536        case SDL_POINTS:
2537            d3dmode = D3DFILL_POINT;
2538            break;
2539        case SDL_WIREFRAME:
2540            d3dmode = D3DFILL_WIREFRAME;
2541            break;
2542        case SDL_SOLID:
2543            d3dmode = D3DFILL_SOLID;
2544            break;
2545
2546        }
2547
2548        HRESULT hr = __SetRenderState(D3DRENDERSTATE_FILLMODE, d3dmode);
2549        if (FAILED(hr))
2550        {
2551            OGRE_EXCEPT(hr, "Error setting rasterisation mode.",
2552                "D3DRenderSystem::setRasterisationMode");
2553        }
2554
2555
2556    }
2557    //---------------------------------------------------------------------
2558    void D3DRenderSystem::setStencilCheckEnabled(bool enabled)
2559    {
2560        // Allow stencilling
2561        HRESULT hr = __SetRenderState(D3DRENDERSTATE_STENCILENABLE, enabled);
2562        if (FAILED(hr))
2563            OGRE_EXCEPT(hr, "Error enabling / disabling stencilling.",
2564            "D3DRenderSystem::setStencilCheckEnabled");
2565
2566    }
2567    //---------------------------------------------------------------------
2568    void D3DRenderSystem::setStencilBufferParams(CompareFunction func,
2569        uint32 refValue, uint32 mask, StencilOperation stencilFailOp,
2570        StencilOperation depthFailOp, StencilOperation passOp,
2571        bool twoSidedOperation)
2572    {
2573        HRESULT hr;
2574
2575        // D3D7 does not support 2-sided stencil operations
2576        if (twoSidedOperation)
2577            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Direct3D7 does not support 2-sided stencil ops",
2578               "D3DRenderSystem::setStencilBufferParams");
2579
2580        // Function
2581        hr = __SetRenderState(D3DRENDERSTATE_STENCILFUNC,
2582            convertCompareFunction(func));
2583
2584        if (FAILED(hr))
2585            OGRE_EXCEPT(hr, "Error setting stencil buffer test function.",
2586            "D3DRenderSystem::setStencilBufferParams");
2587
2588        // reference value
2589        hr = __SetRenderState(D3DRENDERSTATE_STENCILREF, refValue);
2590        if (FAILED(hr))
2591            OGRE_EXCEPT(hr, "Error setting stencil buffer reference value.",
2592            "D3DRenderSystem::setStencilBufferParams");
2593
2594        // mask
2595        hr = __SetRenderState(D3DRENDERSTATE_STENCILMASK, mask);
2596        if (FAILED(hr))
2597            OGRE_EXCEPT(hr, "Error setting stencil buffer mask.",
2598            "D3DRenderSystem::setStencilBufferParams");
2599
2600        // fail op
2601        hr = __SetRenderState(D3DRENDERSTATE_STENCILFAIL,
2602            convertStencilOp(stencilFailOp));
2603        if (FAILED(hr))
2604            OGRE_EXCEPT(hr, "Error setting stencil fail operation.",
2605            "D3DRenderSystem::setStencilBufferParams");
2606
2607        // depth fail op
2608        hr = __SetRenderState(D3DRENDERSTATE_STENCILZFAIL,
2609            convertStencilOp(depthFailOp));
2610        if (FAILED(hr))
2611            OGRE_EXCEPT(hr, "Error setting stencil depth fail operation.",
2612            "D3DRenderSystem::setStencilBufferParams");
2613
2614        // pass op
2615        hr = __SetRenderState(D3DRENDERSTATE_STENCILPASS,
2616            convertStencilOp(passOp));
2617        if (FAILED(hr))
2618            OGRE_EXCEPT(hr, "Error setting stencil pass operation.",
2619            "D3DRenderSystem::setStencilBufferParams");
2620    }
2621    //---------------------------------------------------------------------
2622    D3DCMPFUNC D3DRenderSystem::convertCompareFunction(CompareFunction func)
2623    {
2624        switch(func)
2625        {
2626        case CMPF_ALWAYS_FAIL:
2627            return D3DCMP_NEVER;
2628        case CMPF_ALWAYS_PASS:
2629            return D3DCMP_ALWAYS;
2630        case CMPF_LESS:
2631            return D3DCMP_LESS;
2632        case CMPF_LESS_EQUAL:
2633            return D3DCMP_LESSEQUAL;
2634        case CMPF_EQUAL:
2635            return D3DCMP_EQUAL;
2636        case CMPF_NOT_EQUAL:
2637            return D3DCMP_NOTEQUAL;
2638        case CMPF_GREATER_EQUAL:
2639            return D3DCMP_GREATEREQUAL;
2640        case CMPF_GREATER:
2641            return D3DCMP_GREATER;
2642        };
2643        // to shut the compiler up
2644        return D3DCMP_ALWAYS;
2645    }
2646    //---------------------------------------------------------------------
2647    D3DSTENCILOP D3DRenderSystem::convertStencilOp(StencilOperation op)
2648    {
2649        switch(op)
2650        {
2651        case SOP_KEEP:
2652            return D3DSTENCILOP_KEEP;
2653        case SOP_ZERO:
2654            return D3DSTENCILOP_ZERO;
2655        case SOP_REPLACE:
2656            return D3DSTENCILOP_REPLACE;
2657        case SOP_INCREMENT:
2658            return D3DSTENCILOP_INCRSAT;
2659        case SOP_DECREMENT:
2660            return D3DSTENCILOP_DECRSAT;
2661        case SOP_INCREMENT_WRAP:
2662            return D3DSTENCILOP_INCR;
2663        case SOP_DECREMENT_WRAP:
2664            return D3DSTENCILOP_DECR;
2665        case SOP_INVERT:
2666            return D3DSTENCILOP_INVERT;
2667        };
2668        // To shut the compiler up
2669        return D3DSTENCILOP_KEEP;
2670    }
2671
2672    DWORD D3DRenderSystem::_getCurrentAnisotropy(size_t unit)
2673    {
2674        DWORD oldVal;
2675        mlpD3DDevice->GetTextureStageState(unit, D3DTSS_MAXANISOTROPY, &oldVal);
2676        return oldVal;
2677    }
2678
2679   
2680    void D3DRenderSystem::_setTextureUnitFiltering(size_t unit,
2681        FilterType ftype, FilterOptions filter)
2682    {
2683        __SetTextureStageState(unit, _getFilterCode(ftype), _getFilter(ftype, filter));
2684    }
2685
2686    void D3DRenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy)
2687    {
2688        if ((DWORD)maxAnisotropy > mD3DDeviceDesc.dwMaxAnisotropy)
2689            maxAnisotropy = mD3DDeviceDesc.dwMaxAnisotropy;
2690
2691        if (_getCurrentAnisotropy(unit) != maxAnisotropy)
2692            __SetTextureStageState( unit, D3DTSS_MAXANISOTROPY, maxAnisotropy );
2693    }
2694
2695    void D3DRenderSystem::setVertexDeclaration(VertexDeclaration* decl)
2696    {
2697        // TODO
2698    }
2699
2700    void D3DRenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
2701    {
2702        // TODO
2703    }
2704    //-----------------------------------------------------------------------
2705    D3DTEXTURESTAGESTATETYPE D3DRenderSystem::_getFilterCode(FilterType ft) const
2706    {
2707        switch (ft)
2708        {
2709        case FT_MIN:
2710            return D3DTSS_MINFILTER;
2711            break;
2712        case FT_MAG:
2713            return D3DTSS_MAGFILTER;
2714            break;
2715        case FT_MIP:
2716            return D3DTSS_MIPFILTER;
2717            break;
2718        }
2719
2720        // to keep compiler happy
2721        return D3DTSS_MINFILTER;
2722    }
2723    //-----------------------------------------------------------------------
2724    DWORD D3DRenderSystem::_getFilter(FilterType ft, FilterOptions fo) const
2725    {
2726        switch (ft)
2727        {
2728        case FT_MIN:
2729            switch( fo )
2730            {
2731                // NOTE: Fall through if device doesn't support requested type
2732            case FO_ANISOTROPIC:
2733                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MINFANISOTROPIC )
2734                {
2735                    return D3DTFN_ANISOTROPIC;
2736                    break;
2737                }
2738            case FO_LINEAR:
2739                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR )
2740                {
2741                    return D3DTFN_LINEAR;
2742                    break;
2743                }
2744            case FO_POINT:
2745            case FO_NONE:
2746                return D3DTFN_POINT;
2747                break;
2748            }
2749            break;
2750        case FT_MAG:
2751            switch( fo )
2752            {
2753            // NOTE: Fall through if device doesn't support requested type
2754            case FO_ANISOTROPIC:
2755                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC )
2756                {
2757                    return D3DTFG_ANISOTROPIC;
2758                    break;
2759                }
2760            case FO_LINEAR:
2761                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR )
2762                {
2763                    return D3DTFG_LINEAR;
2764                    break;
2765                }
2766            case FO_POINT:
2767            case FO_NONE:
2768                return D3DTFG_POINT;
2769                break;
2770            }
2771            break;
2772        case FT_MIP:
2773            switch( fo )
2774            {
2775            case FO_ANISOTROPIC:
2776            case FO_LINEAR:
2777                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEARMIPLINEAR )
2778                {
2779                    return D3DTFP_LINEAR;
2780                    break;
2781                }
2782            case FO_POINT:
2783                if( mD3DDeviceDesc.dpcTriCaps.dwTextureFilterCaps & D3DPTFILTERCAPS_LINEAR )
2784                {
2785                    return D3DTFP_POINT;
2786                    break;
2787                }
2788            case FO_NONE:
2789                return D3DTFP_NONE;
2790                break;
2791            }
2792            break;
2793        }
2794
2795        // should never get here
2796        return 0;
2797    }
2798    //---------------------------------------------------------------------
2799    void D3DRenderSystem::setNormaliseNormals(bool normalise)
2800    {
2801        __SetRenderState(D3DRENDERSTATE_NORMALIZENORMALS,
2802            normalise ? TRUE : FALSE);
2803    }
2804    //---------------------------------------------------------------------
2805    HRESULT D3DRenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
2806    {
2807        HRESULT hr;
2808        DWORD oldVal;
2809
2810        if ( FAILED( hr = mlpD3DDevice->GetRenderState(state, &oldVal) ) )
2811            return hr;
2812        if ( oldVal == value )
2813            return D3D_OK;
2814        else
2815            return mlpD3DDevice->SetRenderState(state, value);
2816    }
2817    //---------------------------------------------------------------------
2818    HRESULT D3DRenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
2819    {
2820        HRESULT hr;
2821        DWORD oldVal;
2822
2823        if ( FAILED( hr = mlpD3DDevice->GetTextureStageState(stage, type, &oldVal) ) )
2824            return hr;
2825        if ( oldVal == value )
2826            return D3D_OK;
2827        else
2828            return mlpD3DDevice->SetTextureStageState(stage, type, value);
2829    }
2830
2831    //---------------------------------------------------------------------
2832    void D3DRenderSystem::clearFrameBuffer(unsigned int buffers,
2833        const ColourValue& colour, Real depth, unsigned short stencil)
2834    {
2835                if (mDeviceLost)
2836                        return;
2837
2838                DWORD flags = 0;
2839        if (buffers & FBT_COLOUR)
2840        {
2841            flags |= D3DCLEAR_TARGET;
2842        }
2843        if (buffers & FBT_DEPTH)
2844        {
2845            flags |= D3DCLEAR_ZBUFFER;
2846        }
2847        // Only try to clear the stencil if supported, otherwise it will fail
2848        if (buffers & FBT_STENCIL && mCapabilities->hasCapability(RSC_HWSTENCIL))
2849        {
2850            flags |= D3DCLEAR_STENCIL;
2851        }
2852        HRESULT hr;
2853        if( FAILED( hr = mlpD3DDevice->Clear(
2854            0,
2855            NULL,
2856            flags,
2857            colour.getAsARGB(),
2858            depth,
2859            stencil ) ) )
2860        {
2861            String msg = getErrorDescription(hr);
2862            OGRE_EXCEPT( hr, "Error clearing frame buffer : "
2863                + msg, "D3DRenderSystem::clearFrameBuffer" );
2864        }
2865    }
2866    //---------------------------------------------------------------------
2867    void D3DRenderSystem::_makeProjectionMatrix(Real left, Real right,
2868        Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest,
2869        bool forGpuProgram)
2870    {
2871        Real width = right - left;
2872        Real height = top - bottom;
2873        Real q, qn;
2874        if (farPlane == 0)
2875        {
2876            q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
2877            qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
2878        }
2879        else
2880        {
2881            q = farPlane / ( farPlane - nearPlane );
2882            qn = -q * nearPlane;
2883        }
2884        dest = Matrix4::ZERO;
2885        dest[0][0] = 2 * nearPlane / width;
2886        dest[0][2] = (right+left) / width;
2887        dest[1][1] = 2 * nearPlane / height;
2888        dest[1][2] = (top+bottom) / height;
2889        if (forGpuProgram)
2890        {
2891            dest[2][2] = -q;
2892            dest[3][2] = -1.0f;
2893        }
2894        else
2895        {
2896            dest[2][2] = q;
2897            dest[3][2] = 1.0f;
2898        }
2899        dest[2][3] = qn;
2900    }
2901
2902    //---------------------------------------------------------------------
2903    void D3DRenderSystem::setClipPlanes(const PlaneList& clipPlanes)
2904    {
2905        size_t i;
2906        size_t numClipPlanes;
2907        D3DVALUE dx7ClipPlane[4];
2908        DWORD mask = 0;
2909        HRESULT hr;
2910        numClipPlanes = clipPlanes.size();
2911
2912        for (i = 0; i < numClipPlanes; ++i)
2913        {
2914            const Plane& plane = clipPlanes[i];
2915
2916            dx7ClipPlane[0] = plane.normal.x;
2917            dx7ClipPlane[1] = plane.normal.y;
2918            dx7ClipPlane[2] = plane.normal.z;
2919            dx7ClipPlane[3] = plane.d;
2920
2921            hr = mlpD3DDevice->SetClipPlane(i, dx7ClipPlane);
2922            if (FAILED(hr))
2923            {
2924                OGRE_EXCEPT(hr, "Unable to set clip plane",
2925                    "D3D7RenderSystem::setClipPlanes");
2926            }
2927
2928            mask |= (1 << i);
2929        }
2930
2931        hr = mlpD3DDevice->SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE, mask);
2932        if (FAILED(hr))
2933        {
2934            OGRE_EXCEPT(hr, "Unable to set render state for clip planes",
2935                "D3D7RenderSystem::setClipPlanes");
2936        }
2937    }
2938
2939    // ------------------------------------------------------------------
2940    void D3DRenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D)
2941    {
2942        float plane[4] = { A, B, C, D };
2943        mlpD3DDevice->SetClipPlane (index, plane);
2944    }
2945
2946    // ------------------------------------------------------------------
2947    void D3DRenderSystem::enableClipPlane (ushort index, bool enable)
2948    {
2949        DWORD prev;
2950        mlpD3DDevice->GetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE, &prev);
2951        __SetRenderState(D3DRENDERSTATE_CLIPPLANEENABLE, prev | (1 << index));
2952    }
2953    //---------------------------------------------------------------------
2954    HardwareOcclusionQuery* D3DRenderSystem::createHardwareOcclusionQuery(void)
2955    {
2956        return (HardwareOcclusionQuery*) 0;     // Hardware occlusion is not supported when DirectX7 is used
2957    }
2958    //-----------------------------------------------------------------------
2959    void D3DRenderSystem::_setColourBufferWriteEnabled(bool red, bool green, bool blue, bool alpha)
2960    {
2961        // D3D7 does not have a colour write mask setting, so emulate it using
2962        // scene blending, on the assumption that setSceneBlend will be called
2963        // before this
2964        if (red || green || blue || alpha)
2965        {
2966            // restore saved scene blend
2967            _setSceneBlending(mSavedSrcFactor, mSavedDestFactor);
2968        }
2969        else
2970        {
2971            _setSceneBlending(SBF_ZERO, SBF_ONE);
2972        }
2973    }
2974    //---------------------------------------------------------------------
2975    Real D3DRenderSystem::getHorizontalTexelOffset(void)
2976    {
2977        // D3D considers the origin to be in the center of a pixel
2978        return -0.5f;
2979    }
2980    //---------------------------------------------------------------------
2981    Real D3DRenderSystem::getVerticalTexelOffset(void)
2982    {
2983        // D3D considers the origin to be in the center of a pixel
2984        return -0.5f;
2985    }
2986    //---------------------------------------------------------------------
2987    void D3DRenderSystem::_applyObliqueDepthProjection(Matrix4& matrix,
2988        const Plane& plane, bool forGpuProgram)
2989    {
2990                // Thanks to Eric Lenyel for posting this calculation at www.terathon.com
2991
2992                // Calculate the clip-space corner point opposite the clipping plane
2993                // as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
2994                // transform it into camera space by multiplying it
2995                // by the inverse of the projection matrix
2996
2997                /* generalised version
2998                Vector4 q = matrix.inverse() *
2999                Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f);
3000                */
3001                Vector4 q;
3002                q.x = Math::Sign(plane.normal.x) / matrix[0][0];
3003                q.y = Math::Sign(plane.normal.y) / matrix[1][1];
3004                q.z = 1.0F;
3005                // flip the next bit from Lengyel since we're right-handed
3006                if (forGpuProgram)
3007                {
3008                        q.w = (1.0F - matrix[2][2]) / matrix[2][3];
3009                }
3010                else
3011                {
3012                        q.w = (1.0F + matrix[2][2]) / matrix[2][3];
3013                }
3014
3015                // Calculate the scaled plane vector
3016                Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
3017                Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q)));
3018
3019                // Replace the third row of the projection matrix
3020                matrix[2][0] = c.x;
3021                matrix[2][1] = c.y;
3022                // flip the next bit from Lengyel since we're right-handed
3023                if (forGpuProgram)
3024                {
3025                        matrix[2][2] = c.z;
3026                }
3027                else
3028                {
3029                        matrix[2][2] = -c.z;
3030                }
3031                matrix[2][3] = c.w;       
3032
3033    }
3034    //---------------------------------------------------------------------
3035    Real D3DRenderSystem::getMinimumDepthInputValue(void)
3036    {
3037        // Range [0.0f, 1.0f]
3038        return 0.0f;
3039    }
3040    //---------------------------------------------------------------------
3041    Real D3DRenderSystem::getMaximumDepthInputValue(void)
3042    {
3043        // Range [0.0f, 1.0f]
3044        // D3D inverts even identity view matrices, so maximum INPUT is -1.0
3045        return -1.0f;
3046    }
3047
3048
3049}
Note: See TracBrowser for help on using the repository browser.