1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org
6 
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 
9 Permission is hereby granted, free of charge, to any person obtaining a copy
10 of this software and associated documentation files (the "Software"), to deal
11 in the Software without restriction, including without limitation the rights
12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom the Software is
14 furnished to do so, subject to the following conditions:
15 
16 The above copyright notice and this permission notice shall be included in
17 all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 THE SOFTWARE.
26 -----------------------------------------------------------------------------
27 */
28 #include "OgreD3D9RenderSystem.h"
29 #include "OgreD3D9Prerequisites.h"
30 #include "OgreD3D9DriverList.h"
31 #include "OgreD3D9Driver.h"
32 #include "OgreD3D9VideoModeList.h"
33 #include "OgreD3D9VideoMode.h"
34 #include "OgreD3D9RenderWindow.h"
35 #include "OgreD3D9TextureManager.h"
36 #include "OgreD3D9Texture.h"
37 #include "OgreLogManager.h"
38 #include "OgreLight.h"
39 #include "OgreMath.h"
40 #include "OgreD3D9HardwareBufferManager.h"
41 #include "OgreD3D9HardwareIndexBuffer.h"
42 #include "OgreD3D9HardwareVertexBuffer.h"
43 #include "OgreD3D9VertexDeclaration.h"
44 #include "OgreD3D9GpuProgram.h"
45 #include "OgreD3D9GpuProgramManager.h"
46 #include "OgreD3D9HLSLProgramFactory.h"
47 #include "OgreHighLevelGpuProgramManager.h"
48 #include "OgreD3D9HardwareOcclusionQuery.h"
49 #include "OgreFrustum.h"
50 #include "OgreD3D9MultiRenderTarget.h"
51 #include "OgreCompositorManager.h"
52 #include "OgreD3D9DeviceManager.h"
53 #include "OgreD3D9ResourceManager.h"
54 #include "OgreD3D9DepthBuffer.h"
55 
56 #define FLOAT2DWORD(f) *((DWORD*)&f)
57 
58 namespace Ogre
59 {
60 	D3D9RenderSystem* D3D9RenderSystem::msD3D9RenderSystem = NULL;
61 
62 	//---------------------------------------------------------------------
D3D9RenderSystem(HINSTANCE hInstance)63 	D3D9RenderSystem::D3D9RenderSystem( HINSTANCE hInstance ) :
64 		mMultiheadUse(mutAuto),
65 		mAllowDirectX9Ex(false),
66 		mIsDirectX9Ex(false)
67 	{
68 		LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " created." );
69 
70 		// update singleton access pointer.
71 		msD3D9RenderSystem = this;
72 
73 		// set the instance being passed
74 		mhInstance = hInstance;
75 
76 		// set pointers to NULL
77 		mD3D = NULL;
78 		mDriverList = NULL;
79 		mActiveD3DDriver = NULL;
80 		mTextureManager = NULL;
81 		mHardwareBufferManager = NULL;
82 		mGpuProgramManager = NULL;
83 		mUseNVPerfHUD = false;
84 		mHLSLProgramFactory = NULL;
85 		mDeviceManager = NULL;
86 		mPerStageConstantSupport = false;
87 
88 		// Create the resource manager.
89 		mResourceManager = OGRE_NEW D3D9ResourceManager();
90 
91 
92 		// init lights
93 		for(int i = 0; i < MAX_LIGHTS; i++ )
94 			mLights[i] = 0;
95 
96 		// Create our Direct3D object
97 		if( NULL == (mD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
98 			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" );
99 
100 		// set config options defaults
101 		initConfigOptions();
102 
103 		// fsaa options
104 		mFSAAHint = "";
105 		mFSAASamples = 0;
106 
107 		// set stages desc. to defaults
108 		for (size_t n = 0; n < OGRE_MAX_TEXTURE_LAYERS; n++)
109 		{
110 			mTexStageDesc[n].autoTexCoordType = TEXCALC_NONE;
111 			mTexStageDesc[n].coordIndex = 0;
112 			mTexStageDesc[n].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
113 			mTexStageDesc[n].pTex = 0;
114 			mTexStageDesc[n].pVertexTex = 0;
115 		}
116 
117 		mLastVertexSourceCount = 0;
118 
119 		mCurrentLights.clear();
120 
121 		// Enumerate events
122 		mEventNames.push_back("DeviceLost");
123 		mEventNames.push_back("DeviceRestored");
124 	}
125 	//---------------------------------------------------------------------
~D3D9RenderSystem()126 	D3D9RenderSystem::~D3D9RenderSystem()
127 	{
128 		shutdown();
129 
130 		// Deleting the HLSL program factory
131 		if (mHLSLProgramFactory)
132 		{
133 			// Remove from manager safely
134 			if (HighLevelGpuProgramManager::getSingletonPtr())
135 				HighLevelGpuProgramManager::getSingleton().removeFactory(mHLSLProgramFactory);
136 			OGRE_DELETE mHLSLProgramFactory;
137 			mHLSLProgramFactory = 0;
138 		}
139 
140 		SAFE_RELEASE( mD3D );
141 
142 		if (mResourceManager != NULL)
143 		{
144 			OGRE_DELETE mResourceManager;
145 			mResourceManager = NULL;
146 		}
147 
148 		LogManager::getSingleton().logMessage( "D3D9 : " + getName() + " destroyed." );
149 
150 		msD3D9RenderSystem = NULL;
151 	}
152 	//---------------------------------------------------------------------
getName() const153 	const String& D3D9RenderSystem::getName() const
154 	{
155 		static String strName( "Direct3D9 Rendering Subsystem");
156 		return strName;
157 	}
158 	//---------------------------------------------------------------------
getDirect3DDrivers()159 	D3D9DriverList* D3D9RenderSystem::getDirect3DDrivers()
160 	{
161 		if( !mDriverList )
162 			mDriverList = OGRE_NEW D3D9DriverList();
163 
164 		return mDriverList;
165 	}
166 	//---------------------------------------------------------------------
_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type,DWORD * outQuality,D3DFORMAT format,UINT adapterNum,D3DDEVTYPE deviceType,BOOL fullScreen)167 	bool D3D9RenderSystem::_checkMultiSampleQuality(D3DMULTISAMPLE_TYPE type, DWORD *outQuality, D3DFORMAT format, UINT adapterNum, D3DDEVTYPE deviceType, BOOL fullScreen)
168 	{
169 		HRESULT hr;
170 		hr = mD3D->CheckDeviceMultiSampleType(
171 			adapterNum,
172 			deviceType,
173 			format,
174 			fullScreen,
175 			type,
176 			outQuality);
177 
178 		if (SUCCEEDED(hr))
179 			return true;
180 		else
181 			return false;
182 	}
183 	//---------------------------------------------------------------------
initConfigOptions()184 	void D3D9RenderSystem::initConfigOptions()
185 	{
186 		D3D9DriverList* driverList;
187 		D3D9Driver* driver;
188 
189 		ConfigOption optDevice;
190 		ConfigOption optAllowDirectX9Ex;
191 		ConfigOption optVideoMode;
192 		ConfigOption optFullScreen;
193 		ConfigOption optMultihead;
194 		ConfigOption optVSync;
195 		ConfigOption optVSyncInterval;
196 		ConfigOption optAA;
197 		ConfigOption optFPUMode;
198 		ConfigOption optNVPerfHUD;
199 		ConfigOption optSRGB;
200 		ConfigOption optResourceCeationPolicy;
201 		ConfigOption optMultiDeviceMemHint;
202 		ConfigOption optEnableFixedPipeline;
203 
204 		driverList = this->getDirect3DDrivers();
205 
206 		optDevice.name = "Rendering Device";
207 		optDevice.currentValue.clear();
208 		optDevice.possibleValues.clear();
209 		optDevice.immutable = false;
210 
211 		optAllowDirectX9Ex.name = "Allow DirectX9Ex";
212 		optAllowDirectX9Ex.possibleValues.push_back( "Yes" );
213 		optAllowDirectX9Ex.possibleValues.push_back( "No" );
214 		optAllowDirectX9Ex.currentValue = "No";
215 		optAllowDirectX9Ex.immutable = false;
216 
217 		optVideoMode.name = "Video Mode";
218 		optVideoMode.currentValue = "800 x 600 @ 32-bit colour";
219 		optVideoMode.immutable = false;
220 
221 		optFullScreen.name = "Full Screen";
222 		optFullScreen.possibleValues.push_back( "Yes" );
223 		optFullScreen.possibleValues.push_back( "No" );
224 		optFullScreen.currentValue = "Yes";
225 		optFullScreen.immutable = false;
226 
227 		optMultihead.name = "Use Multihead";
228 		optMultihead.possibleValues.push_back( "Auto" );
229 		optMultihead.possibleValues.push_back( "Yes" );
230 		optMultihead.possibleValues.push_back( "No" );
231 		optMultihead.currentValue = "Auto";
232 		optMultihead.immutable = false;
233 
234 		optResourceCeationPolicy.name = "Resource Creation Policy";
235 		optResourceCeationPolicy.possibleValues.push_back( "Create on all devices" );
236 		optResourceCeationPolicy.possibleValues.push_back( "Create on active device" );
237 
238 		if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ACTIVE_DEVICE)
239 			optResourceCeationPolicy.currentValue = "Create on active device";
240 		else if (mResourceManager->getCreationPolicy() == RCP_CREATE_ON_ALL_DEVICES)
241 			optResourceCeationPolicy.currentValue = "Create on all devices";
242 		else
243 			optResourceCeationPolicy.currentValue = "N/A";
244 		optResourceCeationPolicy.immutable = false;
245 
246 		for( unsigned j=0; j < driverList->count(); j++ )
247 		{
248 			driver = driverList->item(j);
249 			optDevice.possibleValues.push_back( driver->DriverDescription() );
250 			// Make first one default
251 			if( j==0 )
252 				optDevice.currentValue = driver->DriverDescription();
253 		}
254 
255 		optVSync.name = "VSync";
256 		optVSync.immutable = false;
257 		optVSync.possibleValues.push_back( "Yes" );
258 		optVSync.possibleValues.push_back( "No" );
259 		optVSync.currentValue = "No";
260 
261 		optVSyncInterval.name = "VSync Interval";
262 		optVSyncInterval.immutable = false;
263 		optVSyncInterval.possibleValues.push_back( "1" );
264 		optVSyncInterval.possibleValues.push_back( "2" );
265 		optVSyncInterval.possibleValues.push_back( "3" );
266 		optVSyncInterval.possibleValues.push_back( "4" );
267 		optVSyncInterval.currentValue = "1";
268 
269 		optAA.name = "FSAA";
270 		optAA.immutable = false;
271 		optAA.possibleValues.push_back( "None" );
272 		optAA.currentValue = "None";
273 
274 		optFPUMode.name = "Floating-point mode";
275 #if OGRE_DOUBLE_PRECISION
276 		optFPUMode.currentValue = "Consistent";
277 #else
278 		optFPUMode.currentValue = "Fastest";
279 #endif
280 		optFPUMode.possibleValues.clear();
281 		optFPUMode.possibleValues.push_back("Fastest");
282 		optFPUMode.possibleValues.push_back("Consistent");
283 		optFPUMode.immutable = false;
284 
285 		optNVPerfHUD.currentValue = "No";
286 		optNVPerfHUD.immutable = false;
287 		optNVPerfHUD.name = "Allow NVPerfHUD";
288 		optNVPerfHUD.possibleValues.push_back( "Yes" );
289 		optNVPerfHUD.possibleValues.push_back( "No" );
290 
291 
292 		// SRGB on auto window
293 		optSRGB.name = "sRGB Gamma Conversion";
294 		optSRGB.possibleValues.push_back("Yes");
295 		optSRGB.possibleValues.push_back("No");
296 		optSRGB.currentValue = "No";
297 		optSRGB.immutable = false;
298 
299 		// Multiple device memory usage hint.
300 		optMultiDeviceMemHint.name = "Multi device memory hint";
301 		optMultiDeviceMemHint.possibleValues.push_back("Use minimum system memory");
302 		optMultiDeviceMemHint.possibleValues.push_back("Auto hardware buffers management");
303 		optMultiDeviceMemHint.currentValue = "Use minimum system memory";
304 		optMultiDeviceMemHint.immutable = false;
305 
306 		optEnableFixedPipeline.name = "Fixed Pipeline Enabled";
307 		optEnableFixedPipeline.possibleValues.push_back( "Yes" );
308 		optEnableFixedPipeline.possibleValues.push_back( "No" );
309 		optEnableFixedPipeline.currentValue = "Yes";
310 		optEnableFixedPipeline.immutable = false;
311 
312 		mOptions[optDevice.name] = optDevice;
313 		mOptions[optAllowDirectX9Ex.name] = optAllowDirectX9Ex;
314 		mOptions[optVideoMode.name] = optVideoMode;
315 		mOptions[optFullScreen.name] = optFullScreen;
316 		mOptions[optMultihead.name] = optMultihead;
317 		mOptions[optVSync.name] = optVSync;
318 		mOptions[optVSyncInterval.name] = optVSyncInterval;
319 		mOptions[optAA.name] = optAA;
320 		mOptions[optFPUMode.name] = optFPUMode;
321 		mOptions[optNVPerfHUD.name] = optNVPerfHUD;
322 		mOptions[optSRGB.name] = optSRGB;
323 		mOptions[optResourceCeationPolicy.name] = optResourceCeationPolicy;
324 		mOptions[optMultiDeviceMemHint.name] = optMultiDeviceMemHint;
325 		mOptions[optEnableFixedPipeline.name] = optEnableFixedPipeline;
326 
327 		refreshD3DSettings();
328 
329 	}
330 	//---------------------------------------------------------------------
refreshD3DSettings()331 	void D3D9RenderSystem::refreshD3DSettings()
332 	{
333 		ConfigOption* optVideoMode;
334 		D3D9Driver* driver = 0;
335 		D3D9VideoMode* videoMode;
336 
337 		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
338 		if( opt != mOptions.end() )
339 		{
340 			for( unsigned j=0; j < getDirect3DDrivers()->count(); j++ )
341 			{
342 				D3D9Driver* curDriver = getDirect3DDrivers()->item(j);
343 				if( curDriver->DriverDescription() == opt->second.currentValue )
344 				{
345 					driver = curDriver;
346 					break;
347 				}
348 			}
349 
350 			if (driver)
351 			{
352 				opt = mOptions.find( "Video Mode" );
353 				optVideoMode = &opt->second;
354 				optVideoMode->possibleValues.clear();
355 				// get vide modes for this device
356 				for( unsigned k=0; k < driver->getVideoModeList()->count(); k++ )
357 				{
358 					videoMode = driver->getVideoModeList()->item( k );
359 					optVideoMode->possibleValues.push_back( videoMode->getDescription() );
360 				}
361 
362 				// Reset video mode to default if previous doesn't avail in new possible values
363 				StringVector::const_iterator itValue =
364 					std::find(optVideoMode->possibleValues.begin(),
365 					optVideoMode->possibleValues.end(),
366 					optVideoMode->currentValue);
367 				if (itValue == optVideoMode->possibleValues.end())
368 				{
369 					optVideoMode->currentValue = "800 x 600 @ 32-bit colour";
370 				}
371 
372 				// Also refresh FSAA options
373 				refreshFSAAOptions();
374 			}
375 		}
376 
377 	}
378 	//---------------------------------------------------------------------
setConfigOption(const String & name,const String & value)379 	void D3D9RenderSystem::setConfigOption( const String &name, const String &value )
380 	{
381 
382 		LogManager::getSingleton().stream()
383 			<< "D3D9 : RenderSystem Option: " << name << " = " << value;
384 
385 		bool viewModeChanged = false;
386 
387 		// Find option
388 		ConfigOptionMap::iterator it = mOptions.find( name );
389 
390 		// Update
391 		if( it != mOptions.end() )
392 			it->second.currentValue = value;
393 		else
394 		{
395 			StringUtil::StrStreamType str;
396 			str << "Option named '" << name << "' does not exist.";
397 			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, str.str(), "D3D9RenderSystem::setConfigOption" );
398 		}
399 
400 		// Refresh other options if D3DDriver changed
401 		if( name == "Rendering Device" )
402 			refreshD3DSettings();
403 
404 		if ( name == "Allow DirectX9Ex" )
405 		{
406 			if (value == "Yes")
407 				mAllowDirectX9Ex = true;
408 			else mAllowDirectX9Ex = false;
409 
410 			// Create our Direct3D object
411 			if (mAllowDirectX9Ex && !mIsDirectX9Ex)
412 			{
413 				SAFE_RELEASE(mD3D);
414 				HMODULE hD3D = LoadLibrary(TEXT("d3d9.dll"));
415 				if (hD3D)
416 				{
417 					typedef HRESULT (WINAPI *DIRECT3DCREATE9EXFUNCTION)(UINT, IDirect3D9Ex**);
418 					DIRECT3DCREATE9EXFUNCTION pfnCreate9Ex = (DIRECT3DCREATE9EXFUNCTION)GetProcAddress(hD3D, "Direct3DCreate9Ex");
419 					if (pfnCreate9Ex)
420 					{
421 						IDirect3D9Ex* d3dEx = NULL;
422 						(*pfnCreate9Ex)(D3D_SDK_VERSION, &d3dEx);
423 						d3dEx->QueryInterface(__uuidof(IDirect3D9), reinterpret_cast<void **>(&mD3D));
424 						mIsDirectX9Ex = true;
425 					}
426 					FreeLibrary(hD3D);
427 				}
428 			}
429 			if ((mD3D == NULL) || (!mAllowDirectX9Ex && mIsDirectX9Ex))
430 			{
431 				if ( NULL == (mD3D = Direct3DCreate9(D3D_SDK_VERSION)) )
432 					OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Failed to create Direct3D9 object", "D3D9RenderSystem::D3D9RenderSystem" );
433 			}
434 		}
435 
436 		if( name == "Full Screen" )
437 		{
438 			// Video mode is applicable
439 			it = mOptions.find( "Video Mode" );
440 			if (it->second.currentValue.empty())
441 			{
442 				it->second.currentValue = "800 x 600 @ 32-bit colour";
443 				viewModeChanged = true;
444 			}
445 		}
446 
447 		if( name == "Use Multihead" )
448 		{
449 			if (value == "Yes")
450 				mMultiheadUse = mutYes;
451 			else if (value == "No")
452 				mMultiheadUse = mutNo;
453 			else mMultiheadUse = mutAuto;
454 		}
455 
456 		if( name == "FSAA" )
457 		{
458 			StringVector values = StringUtil::split(value, " ", 1);
459 			mFSAASamples = StringConverter::parseUnsignedInt(values[0]);
460 			if (values.size() > 1)
461 				mFSAAHint = values[1];
462 
463 		}
464 
465 		if( name == "Allow NVPerfHUD" )
466 		{
467 			if (value == "Yes")
468 				mUseNVPerfHUD = true;
469 			else
470 				mUseNVPerfHUD = false;
471 		}
472 
473 		if (viewModeChanged || name == "Video Mode")
474 		{
475 			refreshFSAAOptions();
476 		}
477 
478 		if (name == "Resource Creation Policy")
479 		{
480 			if (value == "Create on active device")
481 				mResourceManager->setCreationPolicy(RCP_CREATE_ON_ACTIVE_DEVICE);
482 			else if (value == "Create on all devices")
483 				mResourceManager->setCreationPolicy(RCP_CREATE_ON_ALL_DEVICES);
484 		}
485 
486 		if (name == "Multi device memory hint")
487 		{
488 			if (value == "Use minimum system memory")
489 				mResourceManager->setAutoHardwareBufferManagement(false);
490 			else if (value == "Auto hardware buffers management")
491 				mResourceManager->setAutoHardwareBufferManagement(true);
492 		}
493 
494 		if (name == "Fixed Pipeline Enabled")
495 		{
496 			if (value == "Yes")
497 			{
498 				mEnableFixedPipeline = true;
499 			}
500 			else
501 				mEnableFixedPipeline = false;
502 		}
503 
504 	}
505 	//---------------------------------------------------------------------
refreshFSAAOptions()506 	void D3D9RenderSystem::refreshFSAAOptions()
507 	{
508 
509 		ConfigOptionMap::iterator it = mOptions.find( "FSAA" );
510 		ConfigOption* optFSAA = &it->second;
511 		optFSAA->possibleValues.clear();
512 		optFSAA->possibleValues.push_back("0");
513 
514 		it = mOptions.find("Rendering Device");
515 		D3D9Driver *driver = getDirect3DDrivers()->item(it->second.currentValue);
516 		if (driver)
517 		{
518 			it = mOptions.find("Video Mode");
519 			D3D9VideoMode *videoMode = driver->getVideoModeList()->item(it->second.currentValue);
520 			if (videoMode)
521 			{
522 				DWORD numLevels = 0;
523 				bool bOK;
524 
525 				for (unsigned int n = (unsigned int)D3DMULTISAMPLE_2_SAMPLES; n <= (unsigned int)D3DMULTISAMPLE_16_SAMPLES; n++)
526 				{
527 					bOK = this->_checkMultiSampleQuality(
528 						(D3DMULTISAMPLE_TYPE)n,
529 						&numLevels,
530 						videoMode->getFormat(),
531 						driver->getAdapterNumber(),
532 						D3DDEVTYPE_HAL,
533 						TRUE);
534 					if (bOK)
535 					{
536 						optFSAA->possibleValues.push_back(StringConverter::toString(n));
537 						if (n >= 8)
538 							optFSAA->possibleValues.push_back(StringConverter::toString(n) + " [Quality]");
539 					}
540 				}
541 
542 			}
543 		}
544 
545 		// Reset FSAA to none if previous doesn't avail in new possible values
546 		StringVector::const_iterator itValue =
547 			std::find(optFSAA->possibleValues.begin(),
548 			optFSAA->possibleValues.end(),
549 			optFSAA->currentValue);
550 		if (itValue == optFSAA->possibleValues.end())
551 		{
552 			optFSAA->currentValue = "0";
553 		}
554 
555 	}
556 	//---------------------------------------------------------------------
validateConfigOptions()557 	String D3D9RenderSystem::validateConfigOptions()
558 	{
559 		ConfigOptionMap::iterator it;
560 
561 		// check if video mode is selected
562 		it = mOptions.find( "Video Mode" );
563 		if (it->second.currentValue.empty())
564 			return "A video mode must be selected.";
565 
566 		it = mOptions.find( "Rendering Device" );
567 		bool foundDriver = false;
568 		D3D9DriverList* driverList = getDirect3DDrivers();
569 		for( ushort j=0; j < driverList->count(); j++ )
570 		{
571 			if( driverList->item(j)->DriverDescription() == it->second.currentValue )
572 			{
573 				foundDriver = true;
574 				break;
575 			}
576 		}
577 
578 		if (!foundDriver)
579 		{
580 			// Just pick the first driver
581 			setConfigOption("Rendering Device", driverList->item(0)->DriverDescription());
582 			return "Your DirectX driver name has changed since the last time you ran OGRE; "
583 				"the 'Rendering Device' has been changed.";
584 		}
585 
586 		return StringUtil::BLANK;
587 	}
588 	//---------------------------------------------------------------------
getConfigOptions()589 	ConfigOptionMap& D3D9RenderSystem::getConfigOptions()
590 	{
591 		// return a COPY of the current config options
592 		return mOptions;
593 	}
594 	//---------------------------------------------------------------------
_initialise(bool autoCreateWindow,const String & windowTitle)595 	RenderWindow* D3D9RenderSystem::_initialise( bool autoCreateWindow, const String& windowTitle )
596 	{
597 		RenderWindow* autoWindow = NULL;
598 		LogManager::getSingleton().logMessage( "D3D9 : Subsystem Initialising" );
599 
600 		// Init using current settings
601 		mActiveD3DDriver = NULL;
602 		ConfigOptionMap::iterator opt = mOptions.find( "Rendering Device" );
603 		for( uint j=0; j < getDirect3DDrivers()->count(); j++ )
604 		{
605 			if( getDirect3DDrivers()->item(j)->DriverDescription() == opt->second.currentValue )
606 			{
607 				mActiveD3DDriver = getDirect3DDrivers()->item(j);
608 				break;
609 			}
610 		}
611 
612 		if( !mActiveD3DDriver )
613 			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS, "Problems finding requested Direct3D driver!", "D3D9RenderSystem::initialise" );
614 
615 		// get driver version
616 		mDriverVersion.major = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
617 		mDriverVersion.minor = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.HighPart);
618 		mDriverVersion.release = HIWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
619 		mDriverVersion.build = LOWORD(mActiveD3DDriver->getAdapterIdentifier().DriverVersion.LowPart);
620 
621 		// Create the device manager.
622 		mDeviceManager = OGRE_NEW D3D9DeviceManager();
623 
624 		// Create the texture manager for use by others
625 		mTextureManager = OGRE_NEW D3D9TextureManager();
626 
627 		// Also create hardware buffer manager
628 		mHardwareBufferManager = OGRE_NEW D3D9HardwareBufferManager();
629 
630 		// Create the GPU program manager
631 		mGpuProgramManager = OGRE_NEW D3D9GpuProgramManager();
632 
633 		// Create & register HLSL factory
634 		mHLSLProgramFactory = OGRE_NEW D3D9HLSLProgramFactory();
635 
636 		if( autoCreateWindow )
637 		{
638 			bool fullScreen;
639 			opt = mOptions.find( "Full Screen" );
640 			if( opt == mOptions.end() )
641 				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find full screen option!", "D3D9RenderSystem::initialise" );
642 			fullScreen = opt->second.currentValue == "Yes";
643 
644 			D3D9VideoMode* videoMode = NULL;
645 			unsigned int width, height;
646 			String temp;
647 
648 			opt = mOptions.find( "Video Mode" );
649 			if( opt == mOptions.end() )
650 				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find Video Mode option!", "D3D9RenderSystem::initialise" );
651 
652 			// The string we are manipulating looks like this :width x height @ colourDepth
653 			// Pull out the colour depth by getting what comes after the @ and a space
654 			String colourDepth = opt->second.currentValue.substr(opt->second.currentValue.rfind('@')+1);
655 			// Now we know that the width starts a 0, so if we can find the end we can parse that out
656 			String::size_type widthEnd = opt->second.currentValue.find(' ');
657 			// we know that the height starts 3 characters after the width and goes until the next space
658 			String::size_type heightEnd = opt->second.currentValue.find(' ', widthEnd+3);
659 			// Now we can parse out the values
660 			width = StringConverter::parseInt(opt->second.currentValue.substr(0, widthEnd));
661 			height = StringConverter::parseInt(opt->second.currentValue.substr(widthEnd+3, heightEnd));
662 
663 			for( unsigned j=0; j < mActiveD3DDriver->getVideoModeList()->count(); j++ )
664 			{
665 				temp = mActiveD3DDriver->getVideoModeList()->item(j)->getDescription();
666 
667 				// In full screen we only want to allow supported resolutions, so temp and opt->second.currentValue need to
668 				// match exactly, but in windowed mode we can allow for arbitrary window sized, so we only need
669 				// to match the colour values
670 				if(fullScreen && (temp == opt->second.currentValue) ||
671 					!fullScreen && (temp.substr(temp.rfind('@')+1) == colourDepth))
672 				{
673 					videoMode = mActiveD3DDriver->getVideoModeList()->item(j);
674 					break;
675 				}
676 			}
677 
678 			if( !videoMode )
679 				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find requested video mode.", "D3D9RenderSystem::initialise" );
680 
681 			// sRGB window option
682 			bool hwGamma = false;
683 			opt = mOptions.find( "sRGB Gamma Conversion" );
684 			if( opt == mOptions.end() )
685 				OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Can't find sRGB option!", "D3D9RenderSystem::initialise" );
686 			hwGamma = opt->second.currentValue == "Yes";
687 
688 			NameValuePairList miscParams;
689 			miscParams["colourDepth"] = StringConverter::toString(videoMode->getColourDepth());
690 			miscParams["FSAA"] = StringConverter::toString(mFSAASamples);
691 			miscParams["FSAAHint"] = mFSAAHint;
692 			miscParams["useNVPerfHUD"] = StringConverter::toString(mUseNVPerfHUD);
693 			miscParams["gamma"] = StringConverter::toString(hwGamma);
694 			miscParams["monitorIndex"] = StringConverter::toString(static_cast<int>(mActiveD3DDriver->getAdapterNumber()));
695 
696             opt = mOptions.find("VSync");
697             if (opt == mOptions.end())
698                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find VSync options!", "D3D9RenderSystem::initialise");
699             bool vsync = (opt->second.currentValue == "Yes");
700             miscParams["vsync"] = StringConverter::toString(vsync);
701 
702             opt = mOptions.find("VSync Interval");
703             if (opt == mOptions.end())
704                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Can't find VSync Interval options!", "D3D9RenderSystem::initialise");
705             miscParams["vsyncInterval"] = opt->second.currentValue;
706 
707 			autoWindow = _createRenderWindow( windowTitle, width, height,
708 				fullScreen, &miscParams );
709 
710 			// If we have 16bit depth buffer enable w-buffering.
711 			assert( autoWindow );
712 			if ( autoWindow->getColourDepth() == 16 )
713 			{
714 				mWBuffer = true;
715 			}
716 			else
717 			{
718 				mWBuffer = false;
719 			}
720 		}
721 
722 		LogManager::getSingleton().logMessage("***************************************");
723 		LogManager::getSingleton().logMessage("*** D3D9 : Subsystem Initialised OK ***");
724 		LogManager::getSingleton().logMessage("***************************************");
725 
726 		// call superclass method
727 		RenderSystem::_initialise( autoCreateWindow );
728 
729 
730 		return autoWindow;
731 	}
732 	//---------------------------------------------------------------------
reinitialise()733 	void D3D9RenderSystem::reinitialise()
734 	{
735 		LogManager::getSingleton().logMessage( "D3D9 : Reinitialising" );
736 		this->shutdown();
737 		this->_initialise( true );
738 	}
739 	//---------------------------------------------------------------------
shutdown()740 	void D3D9RenderSystem::shutdown()
741 	{
742 		RenderSystem::shutdown();
743 
744 		if (mDeviceManager != NULL)
745 		{
746 			OGRE_DELETE mDeviceManager;
747 			mDeviceManager = NULL;
748 		}
749 
750 		if (mDriverList != NULL)
751 		{
752 			OGRE_DELETE mDriverList;
753 			mDriverList = NULL;
754 		}
755 		mActiveD3DDriver = NULL;
756 
757 		LogManager::getSingleton().logMessage("D3D9 : Shutting down cleanly.");
758 
759 		if (mTextureManager != NULL)
760 		{
761 			OGRE_DELETE mTextureManager;
762 			mTextureManager = NULL;
763 		}
764 
765 		if (mHardwareBufferManager != NULL)
766 		{
767 			OGRE_DELETE mHardwareBufferManager;
768 			mHardwareBufferManager = NULL;
769 		}
770 
771 		if (mGpuProgramManager != NULL)
772 		{
773 			OGRE_DELETE mGpuProgramManager;
774 			mGpuProgramManager = NULL;
775 		}
776 	}
777 	//---------------------------------------------------------------------
_createRenderWindow(const String & name,unsigned int width,unsigned int height,bool fullScreen,const NameValuePairList * miscParams)778 	RenderWindow* D3D9RenderSystem::_createRenderWindow(const String &name,
779 		unsigned int width, unsigned int height, bool fullScreen,
780 		const NameValuePairList *miscParams)
781 	{
782 		// Log a message
783 		StringStream ss;
784 		ss << "D3D9RenderSystem::_createRenderWindow \"" << name << "\", " <<
785 			width << "x" << height << " ";
786 
787 		if(fullScreen)
788 			ss << "fullscreen ";
789 		else
790 			ss << "windowed ";
791 
792 		if(miscParams)
793 		{
794 			ss << " miscParams: ";
795 			NameValuePairList::const_iterator it;
796 			for(it=miscParams->begin(); it!=miscParams->end(); ++it)
797 			{
798 				ss << it->first << "=" << it->second << " ";
799 			}
800 			LogManager::getSingleton().logMessage(ss.str());
801 		}
802 
803 		String msg;
804 
805 		// Make sure we don't already have a render target of the
806 		// same name as the one supplied
807 		if( mRenderTargets.find( name ) != mRenderTargets.end() )
808 		{
809 			msg = "A render target of the same name '" + name + "' already "
810 				"exists.  You cannot create a new window with this name.";
811 			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, msg, "D3D9RenderSystem::_createRenderWindow" );
812 		}
813 
814 		D3D9RenderWindow* renderWindow = OGRE_NEW D3D9RenderWindow(mhInstance);
815 
816 		renderWindow->create(name, width, height, fullScreen, miscParams);
817 
818 		mResourceManager->lockDeviceAccess();
819 
820         try
821         {
822 		    mDeviceManager->linkRenderWindow(renderWindow);
823         }
824         catch (const Ogre::RenderingAPIException&)
825         {
826             // after catching the exception, clean up
827             mResourceManager->unlockDeviceAccess();
828             renderWindow->destroy();
829 
830             // re-throw
831             throw;
832         }
833 
834 		mResourceManager->unlockDeviceAccess();
835 
836 		mRenderWindows.push_back(renderWindow);
837 
838 		updateRenderSystemCapabilities(renderWindow);
839 
840 		attachRenderTarget( *renderWindow );
841 
842 		return renderWindow;
843 	}
844 	//---------------------------------------------------------------------
_createRenderWindows(const RenderWindowDescriptionList & renderWindowDescriptions,RenderWindowList & createdWindows)845 	bool D3D9RenderSystem::_createRenderWindows(const RenderWindowDescriptionList& renderWindowDescriptions,
846 		RenderWindowList& createdWindows)
847 	{
848 		// Call base render system method.
849 		if (false == RenderSystem::_createRenderWindows(renderWindowDescriptions, createdWindows))
850 			return false;
851 
852 		// Simply call _createRenderWindow in a loop.
853 		for (size_t i = 0; i < renderWindowDescriptions.size(); ++i)
854 		{
855 			const RenderWindowDescription& curRenderWindowDescription = renderWindowDescriptions[i];
856 			RenderWindow* curWindow = NULL;
857 
858 			curWindow = _createRenderWindow(curRenderWindowDescription.name,
859 				curRenderWindowDescription.width,
860 				curRenderWindowDescription.height,
861 				curRenderWindowDescription.useFullScreen,
862 				&curRenderWindowDescription.miscParams);
863 
864 			createdWindows.push_back(curWindow);
865 		}
866 
867 		return true;
868 	}
869 
870 	//---------------------------------------------------------------------
updateRenderSystemCapabilities(D3D9RenderWindow * renderWindow)871 	RenderSystemCapabilities* D3D9RenderSystem::updateRenderSystemCapabilities(D3D9RenderWindow* renderWindow)
872 	{
873 		RenderSystemCapabilities* rsc = mRealCapabilities;
874 		if (rsc == NULL)
875 			rsc = OGRE_NEW RenderSystemCapabilities();
876 
877 		rsc->setCategoryRelevant(CAPS_CATEGORY_D3D9, true);
878 		rsc->setDriverVersion(mDriverVersion);
879 		rsc->setDeviceName(mActiveD3DDriver->DriverDescription());
880 		rsc->setRenderSystemName(getName());
881 
882 		if(mEnableFixedPipeline)
883 		{
884 			// Supports fixed-function
885 			rsc->setCapability(RSC_FIXED_FUNCTION);
886 		}
887 
888 
889 		// Init caps to maximum.
890 		rsc->setNumTextureUnits(1024);
891 		rsc->setCapability(RSC_ANISOTROPY);
892 		rsc->setCapability(RSC_AUTOMIPMAP);
893 		rsc->setCapability(RSC_DOT3);
894 		rsc->setCapability(RSC_CUBEMAPPING);
895 		rsc->setCapability(RSC_SCISSOR_TEST);
896 		rsc->setCapability(RSC_TWO_SIDED_STENCIL);
897 		rsc->setCapability(RSC_STENCIL_WRAP);
898 		rsc->setCapability(RSC_HWOCCLUSION);
899 		rsc->setCapability(RSC_USER_CLIP_PLANES);
900 		rsc->setCapability(RSC_VERTEX_FORMAT_UBYTE4);
901 		rsc->setCapability(RSC_TEXTURE_1D);
902 		rsc->setCapability(RSC_TEXTURE_3D);
903 		rsc->setCapability(RSC_NON_POWER_OF_2_TEXTURES);
904 		rsc->setNonPOW2TexturesLimited(false);
905 		rsc->setNumMultiRenderTargets(OGRE_MAX_MULTIPLE_RENDER_TARGETS);
906 		rsc->setCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS);
907 		rsc->setCapability(RSC_POINT_SPRITES);
908 		rsc->setCapability(RSC_POINT_EXTENDED_PARAMETERS);
909 		rsc->setMaxPointSize(2.19902e+012f);
910 		rsc->setCapability(RSC_MIPMAP_LOD_BIAS);
911 		rsc->setCapability(RSC_PERSTAGECONSTANT);
912 		rsc->setCapability(RSC_HWSTENCIL);
913 		rsc->setStencilBufferBitDepth(8);
914 		rsc->setCapability(RSC_ADVANCED_BLEND_OPERATIONS);
915 		rsc->setCapability(RSC_RTT_SEPARATE_DEPTHBUFFER);
916 		rsc->setCapability(RSC_RTT_MAIN_DEPTHBUFFER_ATTACHABLE);
917 		rsc->setCapability(RSC_RTT_DEPTHBUFFER_RESOLUTION_LESSEQUAL);
918 		rsc->setCapability(RSC_VERTEX_BUFFER_INSTANCE_DATA);
919 		rsc->setCapability(RSC_CAN_GET_COMPILED_SHADER_BUFFER);
920 
921 		for (uint i=0; i < mDeviceManager->getDeviceCount(); ++i)
922 		{
923 			D3D9Device* device			 = mDeviceManager->getDevice(i);
924 			IDirect3DDevice9* d3d9Device = device->getD3D9Device();
925 
926 			IDirect3DSurface9* pSurf;
927 
928 
929 			// Check for hardware stencil support
930 			d3d9Device->GetDepthStencilSurface(&pSurf);
931 
932 			if (pSurf != NULL)
933 			{
934 				D3DSURFACE_DESC surfDesc;
935 
936 				pSurf->GetDesc(&surfDesc);
937 				pSurf->Release();
938 
939 				if (surfDesc.Format != D3DFMT_D15S1 &&
940 					surfDesc.Format != D3DFMT_D24S8 &&
941 					surfDesc.Format != D3DFMT_D24X4S4 &&
942 					surfDesc.Format != D3DFMT_D24FS8)
943 					rsc->unsetCapability(RSC_HWSTENCIL);
944 			}
945 
946 			// Check for hardware occlusion support
947 			HRESULT hr = d3d9Device->CreateQuery(D3DQUERYTYPE_OCCLUSION,  NULL);
948 
949 			if (FAILED(hr))
950 				rsc->unsetCapability(RSC_HWOCCLUSION);
951 		}
952 
953 		// Update RS caps using the minimum value found in adapter list.
954 		for (unsigned int i=0; i < mDriverList->count(); ++i)
955 		{
956 			D3D9Driver* pCurDriver       = mDriverList->item(i);
957 			const D3DCAPS9& rkCurCaps    = pCurDriver->getD3D9DeviceCaps();
958 
959 			if (rkCurCaps.MaxSimultaneousTextures < rsc->getNumTextureUnits())
960 			{
961 				rsc->setNumTextureUnits(static_cast<ushort>(rkCurCaps.MaxSimultaneousTextures));
962 			}
963 
964 			// Check for Anisotropy.
965 			if (rkCurCaps.MaxAnisotropy <= 1)
966 				rsc->unsetCapability(RSC_ANISOTROPY);
967 
968 			// Check automatic mipmap generation.
969 			if ((rkCurCaps.Caps2 & D3DCAPS2_CANAUTOGENMIPMAP) == 0)
970 				rsc->unsetCapability(RSC_AUTOMIPMAP);
971 
972 			// Check Dot product 3.
973 			if ((rkCurCaps.TextureOpCaps & D3DTEXOPCAPS_DOTPRODUCT3) == 0)
974 				rsc->unsetCapability(RSC_DOT3);
975 
976 			// Scissor test
977 			if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_SCISSORTEST) == 0)
978 				rsc->unsetCapability(RSC_SCISSOR_TEST);
979 
980 
981 			// Two-sided stencil
982 			if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_TWOSIDED) == 0)
983 				rsc->unsetCapability(RSC_TWO_SIDED_STENCIL);
984 
985 			// stencil wrap
986 			if ((rkCurCaps.StencilCaps & D3DSTENCILCAPS_INCR) == 0 ||
987 				(rkCurCaps.StencilCaps & D3DSTENCILCAPS_DECR) == 0)
988 				rsc->unsetCapability(RSC_STENCIL_WRAP);
989 
990 			// User clip planes
991 			if (rkCurCaps.MaxUserClipPlanes == 0)
992 				rsc->unsetCapability(RSC_USER_CLIP_PLANES);
993 
994 			// UBYTE4 type?
995 			if ((rkCurCaps.DeclTypes & D3DDTCAPS_UBYTE4) == 0)
996 				rsc->unsetCapability(RSC_VERTEX_FORMAT_UBYTE4);
997 
998 			// Check cube map support.
999 			if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0)
1000 				rsc->unsetCapability(RSC_CUBEMAPPING);
1001 
1002 			// 3D textures?
1003 			if ((rkCurCaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0)
1004 				rsc->unsetCapability(RSC_TEXTURE_3D);
1005 
1006 			if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_POW2)
1007 			{
1008 				// Conditional support for non POW2
1009 				if (rkCurCaps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)
1010 					rsc->setNonPOW2TexturesLimited(true);
1011 
1012 				// Only power of 2 supported.
1013 				else
1014 					rsc->unsetCapability(RSC_NON_POWER_OF_2_TEXTURES);
1015 			}
1016 
1017 			// Number of render targets
1018 			if (rkCurCaps.NumSimultaneousRTs < rsc->getNumMultiRenderTargets())
1019 			{
1020 				rsc->setNumMultiRenderTargets(std::min((ushort)rkCurCaps.NumSimultaneousRTs, (ushort)OGRE_MAX_MULTIPLE_RENDER_TARGETS));
1021 			}
1022 
1023 			if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_MRTINDEPENDENTBITDEPTHS) == 0)
1024 			{
1025 				rsc->unsetCapability(RSC_MRT_DIFFERENT_BIT_DEPTHS);
1026 			}
1027 
1028 			// Point sprites
1029 			if (rkCurCaps.MaxPointSize <= 1.0f)
1030 			{
1031 				rsc->unsetCapability(RSC_POINT_SPRITES);
1032 				// sprites and extended parameters go together in D3D
1033 				rsc->unsetCapability(RSC_POINT_EXTENDED_PARAMETERS);
1034 			}
1035 
1036 			// Take the minimum point size.
1037 			if (rkCurCaps.MaxPointSize < rsc->getMaxPointSize())
1038 				rsc->setMaxPointSize(rkCurCaps.MaxPointSize);
1039 
1040 			// Mipmap LOD biasing?
1041 			if ((rkCurCaps.RasterCaps & D3DPRASTERCAPS_MIPMAPLODBIAS) == 0)
1042 				rsc->unsetCapability(RSC_MIPMAP_LOD_BIAS);
1043 
1044 
1045 			// Do we support per-stage src_manual constants?
1046 			// HACK - ATI drivers seem to be buggy and don't support per-stage constants properly?
1047 			// TODO: move this to RSC
1048 			if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_PERSTAGECONSTANT) == 0)
1049 				rsc->unsetCapability(RSC_PERSTAGECONSTANT);
1050 
1051 			// Advanced blend operations? min max subtract rev
1052 			if((rkCurCaps.PrimitiveMiscCaps & D3DPMISCCAPS_BLENDOP) == 0)
1053 				rsc->unsetCapability(RSC_ADVANCED_BLEND_OPERATIONS);
1054 		}
1055 
1056 		// Blending between stages supported
1057 		rsc->setCapability(RSC_BLENDING);
1058 
1059 
1060 		// We always support compression, D3DX will decompress if device does not support
1061 		rsc->setCapability(RSC_TEXTURE_COMPRESSION);
1062 		rsc->setCapability(RSC_TEXTURE_COMPRESSION_DXT);
1063 
1064 		// We always support VBOs
1065 		rsc->setCapability(RSC_VBO);
1066 
1067 
1068 		convertVertexShaderCaps(rsc);
1069 		convertPixelShaderCaps(rsc);
1070 
1071 		// Adapter details
1072 		const D3DADAPTER_IDENTIFIER9& adapterID = mActiveD3DDriver->getAdapterIdentifier();
1073 
1074 		// determine vendor
1075 		// Full list of vendors here: http://www.pcidatabase.com/vendors.php?sort=id
1076 		switch(adapterID.VendorId)
1077 		{
1078 		case 0x10DE:
1079 			rsc->setVendor(GPU_NVIDIA);
1080 			break;
1081 		case 0x1002:
1082 			rsc->setVendor(GPU_AMD);
1083 			break;
1084 		case 0x163C:
1085 		case 0x8086:
1086 			rsc->setVendor(GPU_INTEL);
1087 			break;
1088 		case 0x5333:
1089 			rsc->setVendor(GPU_S3);
1090 			break;
1091 		case 0x3D3D:
1092 			rsc->setVendor(GPU_3DLABS);
1093 			break;
1094 		case 0x102B:
1095 			rsc->setVendor(GPU_MATROX);
1096 			break;
1097 		case 0x1039:
1098 			rsc->setVendor(GPU_SIS);
1099 			break;
1100 		default:
1101 			rsc->setVendor(GPU_UNKNOWN);
1102 			break;
1103 		};
1104 
1105 		// Infinite projection?
1106 		// We have no capability for this, so we have to base this on our
1107 		// experience and reports from users
1108 		// Non-vertex program capable hardware does not appear to support it
1109 		if (rsc->hasCapability(RSC_VERTEX_PROGRAM))
1110 		{
1111 			// GeForce4 Ti (and presumably GeForce3) does not
1112 			// render infinite projection properly, even though it does in GL
1113 			// So exclude all cards prior to the FX range from doing infinite
1114 			if (rsc->getVendor() != GPU_NVIDIA || // not nVidia
1115 				!((adapterID.DeviceId >= 0x200 && adapterID.DeviceId <= 0x20F) || //gf3
1116 				(adapterID.DeviceId >= 0x250 && adapterID.DeviceId <= 0x25F) || //gf4ti
1117 				(adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F) || //gf4ti
1118 				(adapterID.DeviceId >= 0x170 && adapterID.DeviceId <= 0x18F) || //gf4 go
1119 				(adapterID.DeviceId >= 0x280 && adapterID.DeviceId <= 0x28F)))  //gf4ti go
1120 			{
1121 				rsc->setCapability(RSC_INFINITE_FAR_PLANE);
1122 			}
1123 
1124 		}
1125 
1126 		// We always support rendertextures bigger than the frame buffer
1127 		rsc->setCapability(RSC_HWRENDER_TO_TEXTURE);
1128 
1129 		// Determine if any floating point texture format is supported
1130 		D3DFORMAT floatFormats[6] = {D3DFMT_R16F, D3DFMT_G16R16F,
1131 			D3DFMT_A16B16G16R16F, D3DFMT_R32F, D3DFMT_G32R32F,
1132 			D3DFMT_A32B32G32R32F};
1133 		IDirect3DSurface9* bbSurf;
1134 		renderWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf);
1135 		D3DSURFACE_DESC bbSurfDesc;
1136 		bbSurf->GetDesc(&bbSurfDesc);
1137 
1138 		for (int i = 0; i < 6; ++i)
1139 		{
1140 			if (SUCCEEDED(mD3D->CheckDeviceFormat(mActiveD3DDriver->getAdapterNumber(),
1141 				D3DDEVTYPE_HAL, bbSurfDesc.Format,
1142 				0, D3DRTYPE_TEXTURE, floatFormats[i])))
1143 			{
1144 				rsc->setCapability(RSC_TEXTURE_FLOAT);
1145 				break;
1146 			}
1147 
1148 		}
1149 
1150 
1151 		// TODO: make convertVertex/Fragment fill in rsc
1152 		// TODO: update the below line to use rsc
1153 		// Vertex textures
1154 		if (rsc->isShaderProfileSupported("vs_3_0"))
1155 		{
1156 			// Run through all the texture formats looking for any which support
1157 			// vertex texture fetching. Must have at least one!
1158 			// All ATI Radeon up to X1n00 say they support vs_3_0,
1159 			// but they support no texture formats for vertex texture fetch (cheaters!)
1160 			if (checkVertexTextureFormats(renderWindow))
1161 			{
1162 				rsc->setCapability(RSC_VERTEX_TEXTURE_FETCH);
1163 				// always 4 vertex texture units in vs_3_0, and never shared
1164 				rsc->setNumVertexTextureUnits(4);
1165 				rsc->setVertexTextureUnitsShared(false);
1166 			}
1167 		}
1168 		else
1169 		{
1170 			//True HW Instancing is supported since Shader model 3.0 ATI has a nasty
1171 			//hack for enabling it in their SM 2.0 cards, but we don't (and won't) support it
1172 			rsc->unsetCapability( RSC_VERTEX_BUFFER_INSTANCE_DATA );
1173 		}
1174 
1175 		// Check alpha to coverage support
1176 		// this varies per vendor! But at least SM3 is required
1177 		if (rsc->isShaderProfileSupported("ps_3_0"))
1178 		{
1179 			// NVIDIA needs a separate check
1180 			if (rsc->getVendor() == GPU_NVIDIA)
1181 			{
1182 				if (mD3D->CheckDeviceFormat(
1183 						D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE,
1184 						(D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK)
1185 				{
1186 					rsc->setCapability(RSC_ALPHA_TO_COVERAGE);
1187 				}
1188 
1189 			}
1190 			else if (rsc->getVendor() == GPU_AMD)
1191 			{
1192 				// There is no check on ATI, we have to assume SM3 == support
1193 				rsc->setCapability(RSC_ALPHA_TO_COVERAGE);
1194 			}
1195 
1196 			// no other cards have Dx9 hacks for alpha to coverage, as far as I know
1197 		}
1198 
1199 
1200 		if (mRealCapabilities == NULL)
1201 		{
1202 			mRealCapabilities = rsc;
1203 			mRealCapabilities->addShaderProfile("hlsl");
1204 
1205 			// if we are using custom capabilities, then
1206 			// mCurrentCapabilities has already been loaded
1207 			if(!mUseCustomCapabilities)
1208 				mCurrentCapabilities = mRealCapabilities;
1209 
1210             fireEvent("RenderSystemCapabilitiesCreated");
1211 
1212 			initialiseFromRenderSystemCapabilities(mCurrentCapabilities, renderWindow);
1213 		}
1214 
1215 		return rsc;
1216 	}
1217 	//---------------------------------------------------------------------
convertVertexShaderCaps(RenderSystemCapabilities * rsc) const1218 	void D3D9RenderSystem::convertVertexShaderCaps(RenderSystemCapabilities* rsc) const
1219 	{
1220 		ushort major = 0xFF;
1221 		ushort minor = 0xFF;
1222 		D3DCAPS9 minVSCaps;
1223 
1224 		// Find the device with the lowest vertex shader caps.
1225 		for (unsigned int i=0; i < mDriverList->count(); ++i)
1226 		{
1227 			D3D9Driver* pCurDriver      = mDriverList->item(i);
1228 			const D3DCAPS9& rkCurCaps   = pCurDriver->getD3D9DeviceCaps();
1229 			ushort currMajor			= static_cast<ushort>((rkCurCaps.VertexShaderVersion & 0x0000FF00) >> 8);
1230 			ushort currMinor			= static_cast<ushort>(rkCurCaps.VertexShaderVersion & 0x000000FF);
1231 
1232 			if (currMajor < major)
1233 			{
1234 				major = currMajor;
1235 				minor = currMinor;
1236 				minVSCaps = rkCurCaps;
1237 			}
1238 			else if (currMajor == major && currMinor < minor)
1239 			{
1240 				minor = currMinor;
1241 				minVSCaps = rkCurCaps;
1242 			}
1243 		}
1244 
1245 		// In case we didn't found any vertex shader support
1246 		// try the IDirect3DDevice9 caps instead of the IDirect3D9
1247 		// software vertex processing is reported there
1248 		if (major == 0 && minor == 0)
1249 		{
1250 			IDirect3DDevice9* lpD3DDevice9 = getActiveD3D9Device();
1251 			D3DCAPS9 d3dDeviceCaps9;
1252 			lpD3DDevice9->GetDeviceCaps(&d3dDeviceCaps9);
1253 			major = static_cast<ushort>((d3dDeviceCaps9.VertexShaderVersion & 0x0000FF00) >> 8);
1254 			minor = static_cast<ushort>(d3dDeviceCaps9.VertexShaderVersion & 0x000000FF);
1255 		}
1256 
1257 		bool vs2x = false;
1258 		bool vs2a = false;
1259 
1260 		// Special case detection for vs_2_x/a support
1261 		if (major >= 2)
1262 		{
1263 			if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
1264 				(minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
1265 				(minVSCaps.VS20Caps.NumTemps >= 12))
1266 			{
1267 				vs2x = true;
1268 			}
1269 
1270 			if ((minVSCaps.VS20Caps.Caps & D3DVS20CAPS_PREDICATION) &&
1271 				(minVSCaps.VS20Caps.DynamicFlowControlDepth > 0) &&
1272 				(minVSCaps.VS20Caps.NumTemps >= 13))
1273 			{
1274 				vs2a = true;
1275 			}
1276 		}
1277 
1278 		// Populate max param count
1279 		switch (major)
1280 		{
1281 		case 1:
1282 			// No boolean params allowed
1283 			rsc->setVertexProgramConstantBoolCount(0);
1284 			// No integer params allowed
1285 			rsc->setVertexProgramConstantIntCount(0);
1286 			// float params, always 4D
1287 			rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst));
1288 
1289 			break;
1290 		case 2:
1291 			// 16 boolean params allowed
1292 			rsc->setVertexProgramConstantBoolCount(16);
1293 			// 16 integer params allowed, 4D
1294 			rsc->setVertexProgramConstantIntCount(16);
1295 			// float params, always 4D
1296 			rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst));
1297 			break;
1298 		case 3:
1299 			// 16 boolean params allowed
1300 			rsc->setVertexProgramConstantBoolCount(16);
1301 			// 16 integer params allowed, 4D
1302 			rsc->setVertexProgramConstantIntCount(16);
1303 			// float params, always 4D
1304 			rsc->setVertexProgramConstantFloatCount(static_cast<ushort>(minVSCaps.MaxVertexShaderConst));
1305 			break;
1306 		}
1307 
1308 		// populate syntax codes in program manager (no breaks in this one so it falls through)
1309 		switch(major)
1310 		{
1311 		case 3:
1312 			rsc->addShaderProfile("vs_3_0");
1313 		case 2:
1314 			if (vs2x)
1315 				rsc->addShaderProfile("vs_2_x");
1316 			if (vs2a)
1317 				rsc->addShaderProfile("vs_2_a");
1318 
1319 			rsc->addShaderProfile("vs_2_0");
1320 		case 1:
1321 			rsc->addShaderProfile("vs_1_1");
1322 			rsc->setCapability(RSC_VERTEX_PROGRAM);
1323 		}
1324 	}
1325 	//---------------------------------------------------------------------
convertPixelShaderCaps(RenderSystemCapabilities * rsc) const1326 	void D3D9RenderSystem::convertPixelShaderCaps(RenderSystemCapabilities* rsc) const
1327 	{
1328 		ushort major = 0xFF;
1329 		ushort minor = 0xFF;
1330 		D3DCAPS9 minPSCaps;
1331 
1332 		// Find the device with the lowest pixel shader caps.
1333 		for (unsigned int i=0; i < mDriverList->count(); ++i)
1334 		{
1335 			D3D9Driver* pCurDriver      = mDriverList->item(i);
1336 			const D3DCAPS9& currCaps    = pCurDriver->getD3D9DeviceCaps();
1337 			ushort currMajor			= static_cast<ushort>((currCaps.PixelShaderVersion & 0x0000FF00) >> 8);
1338 			ushort currMinor			= static_cast<ushort>(currCaps.PixelShaderVersion & 0x000000FF);
1339 
1340 			if (currMajor < major)
1341 			{
1342 				major = currMajor;
1343 				minor = currMinor;
1344 				minPSCaps = currCaps;
1345 			}
1346 			else if (currMajor == major && currMinor < minor)
1347 			{
1348 				minor = currMinor;
1349 				minPSCaps = currCaps;
1350 			}
1351 		}
1352 
1353 		bool ps2a = false;
1354 		bool ps2b = false;
1355 		bool ps2x = false;
1356 
1357 		// Special case detection for ps_2_x/a/b support
1358 		if (major >= 2)
1359 		{
1360 			if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
1361 				(minPSCaps.PS20Caps.NumTemps >= 32))
1362 			{
1363 				ps2b = true;
1364 			}
1365 
1366 			if ((minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NOTEXINSTRUCTIONLIMIT) &&
1367 				(minPSCaps.PS20Caps.Caps & D3DPS20CAPS_NODEPENDENTREADLIMIT) &&
1368 				(minPSCaps.PS20Caps.Caps & D3DPS20CAPS_ARBITRARYSWIZZLE) &&
1369 				(minPSCaps.PS20Caps.Caps & D3DPS20CAPS_GRADIENTINSTRUCTIONS) &&
1370 				(minPSCaps.PS20Caps.Caps & D3DPS20CAPS_PREDICATION) &&
1371 				(minPSCaps.PS20Caps.NumTemps >= 22))
1372 			{
1373 				ps2a = true;
1374 			}
1375 
1376 			// Does this enough?
1377 			if (ps2a || ps2b)
1378 			{
1379 				ps2x = true;
1380 			}
1381 		}
1382 
1383 		switch (major)
1384 		{
1385 		case 1:
1386 			// no boolean params allowed
1387 			rsc->setFragmentProgramConstantBoolCount(0);
1388 			// no integer params allowed
1389 			rsc->setFragmentProgramConstantIntCount(0);
1390 			// float params, always 4D
1391 			// NB in ps_1_x these are actually stored as fixed point values,
1392 			// but they are entered as floats
1393 			rsc->setFragmentProgramConstantFloatCount(8);
1394 			break;
1395 		case 2:
1396 			// 16 boolean params allowed
1397 			rsc->setFragmentProgramConstantBoolCount(16);
1398 			// 16 integer params allowed, 4D
1399 			rsc->setFragmentProgramConstantIntCount(16);
1400 			// float params, always 4D
1401 			rsc->setFragmentProgramConstantFloatCount(32);
1402 			break;
1403 		case 3:
1404 			// 16 boolean params allowed
1405 			rsc->setFragmentProgramConstantBoolCount(16);
1406 			// 16 integer params allowed, 4D
1407 			rsc->setFragmentProgramConstantIntCount(16);
1408 			// float params, always 4D
1409 			rsc->setFragmentProgramConstantFloatCount(224);
1410 			break;
1411 		}
1412 
1413 		// populate syntax codes in program manager (no breaks in this one so it falls through)
1414 		switch(major)
1415 		{
1416 		case 3:
1417 			if (minor > 0)
1418 				rsc->addShaderProfile("ps_3_x");
1419 
1420 			rsc->addShaderProfile("ps_3_0");
1421 		case 2:
1422 			if (ps2x)
1423 				rsc->addShaderProfile("ps_2_x");
1424 			if (ps2a)
1425 				rsc->addShaderProfile("ps_2_a");
1426 			if (ps2b)
1427 				rsc->addShaderProfile("ps_2_b");
1428 
1429 			rsc->addShaderProfile("ps_2_0");
1430 		case 1:
1431 			if (major > 1 || minor >= 4)
1432 				rsc->addShaderProfile("ps_1_4");
1433 			if (major > 1 || minor >= 3)
1434 				rsc->addShaderProfile("ps_1_3");
1435 			if (major > 1 || minor >= 2)
1436 				rsc->addShaderProfile("ps_1_2");
1437 
1438 			rsc->addShaderProfile("ps_1_1");
1439 			rsc->setCapability(RSC_FRAGMENT_PROGRAM);
1440 		}
1441 	}
1442 	//-----------------------------------------------------------------------
checkVertexTextureFormats(D3D9RenderWindow * renderWindow) const1443 	bool D3D9RenderSystem::checkVertexTextureFormats(D3D9RenderWindow* renderWindow) const
1444 	{
1445 		bool anySupported = false;
1446 
1447 		IDirect3DSurface9* bbSurf;
1448 		renderWindow->getCustomAttribute("DDBACKBUFFER", &bbSurf);
1449 		D3DSURFACE_DESC bbSurfDesc;
1450 		bbSurf->GetDesc(&bbSurfDesc);
1451 
1452 		for (uint ipf = static_cast<uint>(PF_L8); ipf < static_cast<uint>(PF_COUNT); ++ipf)
1453 		{
1454 			PixelFormat pf = (PixelFormat)ipf;
1455 
1456 			D3DFORMAT fmt =
1457 				D3D9Mappings::_getPF(D3D9Mappings::_getClosestSupportedPF(pf));
1458 
1459 			if (SUCCEEDED(mD3D->CheckDeviceFormat(
1460 				mActiveD3DDriver->getAdapterNumber(), D3DDEVTYPE_HAL, bbSurfDesc.Format,
1461 				D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, fmt)))
1462 			{
1463 				// cool, at least one supported
1464 				anySupported = true;
1465 				LogManager::getSingleton().stream()
1466 					<< "D3D9: Vertex texture format supported - "
1467 					<< PixelUtil::getFormatName(pf);
1468 			}
1469 		}
1470 
1471 		return anySupported;
1472 
1473 	}
1474 	//-----------------------------------------------------------------------
initialiseFromRenderSystemCapabilities(RenderSystemCapabilities * caps,RenderTarget * primary)1475 	void D3D9RenderSystem::initialiseFromRenderSystemCapabilities(RenderSystemCapabilities* caps, RenderTarget* primary)
1476 	{
1477 		if (caps->getRenderSystemName() != getName())
1478 		{
1479 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1480 				"Trying to initialize D3D9RenderSystem from RenderSystemCapabilities that do not support Direct3D9",
1481 				"D3D9RenderSystem::initialiseFromRenderSystemCapabilities");
1482 		}
1483 		if (caps->isShaderProfileSupported("hlsl"))
1484 			HighLevelGpuProgramManager::getSingleton().addFactory(mHLSLProgramFactory);
1485 
1486 		Log* defaultLog = LogManager::getSingleton().getDefaultLog();
1487 		if (defaultLog)
1488 		{
1489 			caps->log(defaultLog);
1490 		}
1491 	}
1492 
1493 	//-----------------------------------------------------------------------
_checkTextureFilteringSupported(TextureType ttype,PixelFormat format,int usage)1494 	bool D3D9RenderSystem::_checkTextureFilteringSupported(TextureType ttype, PixelFormat format, int usage)
1495 	{
1496 		// Gets D3D format
1497 		D3DFORMAT d3dPF = D3D9Mappings::_getPF(format);
1498 		if (d3dPF == D3DFMT_UNKNOWN)
1499 			return false;
1500 
1501 		for (uint i = 0; i < mDeviceManager->getDeviceCount(); ++i)
1502 		{
1503 			D3D9Device* currDevice = mDeviceManager->getDevice(i);
1504 			D3D9RenderWindow* currDevicePrimaryWindow = currDevice->getPrimaryWindow();
1505 			IDirect3DSurface9* pSurface = currDevicePrimaryWindow->getRenderSurface();
1506 			D3DSURFACE_DESC srfDesc;
1507 
1508 			// Get surface desc
1509 			if (FAILED(pSurface->GetDesc(&srfDesc)))
1510 				return false;
1511 
1512 			// Calculate usage
1513 			DWORD d3dusage = D3DUSAGE_QUERY_FILTER;
1514 			if (usage & TU_RENDERTARGET)
1515 				d3dusage |= D3DUSAGE_RENDERTARGET;
1516 			if (usage & TU_DYNAMIC)
1517 				d3dusage |= D3DUSAGE_DYNAMIC;
1518 
1519 			// Detect resource type
1520 			D3DRESOURCETYPE rtype;
1521 			switch(ttype)
1522 			{
1523 			case TEX_TYPE_1D:
1524 			case TEX_TYPE_2D:
1525 				rtype = D3DRTYPE_TEXTURE;
1526 				break;
1527 			case TEX_TYPE_3D:
1528 				rtype = D3DRTYPE_VOLUMETEXTURE;
1529 				break;
1530 			case TEX_TYPE_CUBE_MAP:
1531 				rtype = D3DRTYPE_CUBETEXTURE;
1532 				break;
1533 			default:
1534 				return false;
1535 			}
1536 
1537 			HRESULT hr = mD3D->CheckDeviceFormat(
1538 				currDevice->getAdapterNumber(),
1539 				currDevice->getDeviceType(),
1540 				srfDesc.Format,
1541 				d3dusage,
1542 				rtype,
1543 				d3dPF);
1544 
1545 			if (FAILED(hr))
1546 				return false;
1547 		}
1548 
1549 		return true;
1550 	}
1551 	//-----------------------------------------------------------------------
createMultiRenderTarget(const String & name)1552 	MultiRenderTarget * D3D9RenderSystem::createMultiRenderTarget(const String & name)
1553 	{
1554 		MultiRenderTarget *retval;
1555 		retval = OGRE_NEW D3D9MultiRenderTarget(name);
1556 		attachRenderTarget(*retval);
1557 
1558 		return retval;
1559 	}
1560 	//---------------------------------------------------------------------
detachRenderTarget(const String & name)1561 	RenderTarget* D3D9RenderSystem::detachRenderTarget(const String &name)
1562 	{
1563 		RenderTarget* target = RenderSystem::detachRenderTarget(name);
1564 		detachRenderTargetImpl(name);
1565 		return target;
1566 	}
1567 	//---------------------------------------------------------------------
detachRenderTargetImpl(const String & name)1568 	void D3D9RenderSystem::detachRenderTargetImpl(const String& name)
1569 	{
1570 		// Check render windows
1571 		D3D9RenderWindowList::iterator sw;
1572 		for (sw = mRenderWindows.begin(); sw != mRenderWindows.end(); ++sw)
1573 		{
1574 			if ((*sw)->getName() == name)
1575 			{
1576 				mRenderWindows.erase(sw);
1577 				break;
1578 			}
1579 		}
1580 	}
1581 	//---------------------------------------------------------------------
destroyRenderTarget(const String & name)1582 	void D3D9RenderSystem::destroyRenderTarget(const String& name)
1583 	{
1584 		detachRenderTargetImpl(name);
1585 
1586 		// Do the real removal
1587 		RenderSystem::destroyRenderTarget(name);
1588 	}
1589 	//---------------------------------------------------------------------
getErrorDescription(long errorNumber) const1590 	String D3D9RenderSystem::getErrorDescription( long errorNumber ) const
1591 	{
1592 		const String errMsg = DXGetErrorDescription( errorNumber );
1593 		return errMsg;
1594 	}
1595 	//---------------------------------------------------------------------
getColourVertexElementType() const1596 	VertexElementType D3D9RenderSystem::getColourVertexElementType() const
1597 	{
1598 		return VET_COLOUR_ARGB;
1599 	}
1600 	//---------------------------------------------------------------------
_convertProjectionMatrix(const Matrix4 & matrix,Matrix4 & dest,bool forGpuProgram)1601 	void D3D9RenderSystem::_convertProjectionMatrix(const Matrix4& matrix,
1602 		Matrix4& dest, bool forGpuProgram)
1603 	{
1604 		dest = matrix;
1605 
1606 		// Convert depth range from [-1,+1] to [0,1]
1607 		dest[2][0] = (dest[2][0] + dest[3][0]) / 2;
1608 		dest[2][1] = (dest[2][1] + dest[3][1]) / 2;
1609 		dest[2][2] = (dest[2][2] + dest[3][2]) / 2;
1610 		dest[2][3] = (dest[2][3] + dest[3][3]) / 2;
1611 
1612 		if (!forGpuProgram)
1613 		{
1614 			// Convert right-handed to left-handed
1615 			dest[0][2] = -dest[0][2];
1616 			dest[1][2] = -dest[1][2];
1617 			dest[2][2] = -dest[2][2];
1618 			dest[3][2] = -dest[3][2];
1619 		}
1620 	}
1621 	//---------------------------------------------------------------------
_makeProjectionMatrix(const Radian & fovy,Real aspect,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)1622 	void D3D9RenderSystem::_makeProjectionMatrix(const Radian& fovy, Real aspect, Real nearPlane,
1623 		Real farPlane, Matrix4& dest, bool forGpuProgram)
1624 	{
1625 		Radian theta ( fovy * 0.5 );
1626 		Real h = 1 / Math::Tan(theta);
1627 		Real w = h / aspect;
1628 		Real q, qn;
1629 		if (farPlane == 0)
1630 		{
1631 			q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
1632 			qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
1633 		}
1634 		else
1635 		{
1636 			q = farPlane / ( farPlane - nearPlane );
1637 			qn = -q * nearPlane;
1638 		}
1639 
1640 		dest = Matrix4::ZERO;
1641 		dest[0][0] = w;
1642 		dest[1][1] = h;
1643 
1644 		if (forGpuProgram)
1645 		{
1646 			dest[2][2] = -q;
1647 			dest[3][2] = -1.0f;
1648 		}
1649 		else
1650 		{
1651 			dest[2][2] = q;
1652 			dest[3][2] = 1.0f;
1653 		}
1654 
1655 		dest[2][3] = qn;
1656 	}
1657 	//---------------------------------------------------------------------
_makeOrthoMatrix(const Radian & fovy,Real aspect,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)1658 	void D3D9RenderSystem::_makeOrthoMatrix(const Radian& fovy, Real aspect, Real nearPlane, Real farPlane,
1659 		Matrix4& dest, bool forGpuProgram )
1660 	{
1661 		Radian thetaY (fovy / 2.0f);
1662 		Real tanThetaY = Math::Tan(thetaY);
1663 
1664 		//Real thetaX = thetaY * aspect;
1665 		Real tanThetaX = tanThetaY * aspect; //Math::Tan(thetaX);
1666 		Real half_w = tanThetaX * nearPlane;
1667 		Real half_h = tanThetaY * nearPlane;
1668 		Real iw = static_cast<Real>(1.0 / half_w);
1669 		Real ih = static_cast<Real>(1.0 / half_h);
1670 		Real q;
1671 		if (farPlane == 0)
1672 		{
1673 			q = 0;
1674 		}
1675 		else
1676 		{
1677 			q = static_cast<Real>(1.0 / (farPlane - nearPlane));
1678 		}
1679 
1680 		dest = Matrix4::ZERO;
1681 		dest[0][0] = iw;
1682 		dest[1][1] = ih;
1683 		dest[2][2] = q;
1684 		dest[2][3] = -nearPlane / (farPlane - nearPlane);
1685 		dest[3][3] = 1;
1686 
1687 		if (forGpuProgram)
1688 		{
1689 			dest[2][2] = -dest[2][2];
1690 		}
1691 	}
1692 	//---------------------------------------------------------------------
setAmbientLight(float r,float g,float b)1693 	void D3D9RenderSystem::setAmbientLight( float r, float g, float b )
1694 	{
1695 		HRESULT hr = __SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( r, g, b, 1.0f ) );
1696 		if( FAILED( hr ) )
1697 			OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
1698 			"Failed to set render stat D3DRS_AMBIENT", "D3D9RenderSystem::setAmbientLight" );
1699 	}
1700 	//---------------------------------------------------------------------
_useLights(const LightList & lights,unsigned short limit)1701 	void D3D9RenderSystem::_useLights(const LightList& lights, unsigned short limit)
1702 	{
1703 		IDirect3DDevice9* activeDevice = getActiveD3D9Device();
1704 		LightList::const_iterator i, iend;
1705 		iend = lights.end();
1706 		unsigned short num = 0;
1707 		for (i = lights.begin(); i != iend && num < limit; ++i, ++num)
1708 		{
1709 			setD3D9Light(num, *i);
1710 		}
1711 		// Disable extra lights
1712 		for (; num < mCurrentLights[activeDevice]; ++num)
1713 		{
1714 			setD3D9Light(num, NULL);
1715 		}
1716 		mCurrentLights[activeDevice] = std::min(limit, static_cast<unsigned short>(lights.size()));
1717 
1718 	}
1719 	//---------------------------------------------------------------------
setShadingType(ShadeOptions so)1720 	void D3D9RenderSystem::setShadingType( ShadeOptions so )
1721 	{
1722 		HRESULT hr = __SetRenderState( D3DRS_SHADEMODE, D3D9Mappings::get(so) );
1723 		if( FAILED( hr ) )
1724 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
1725 			"Failed to set render stat D3DRS_SHADEMODE", "D3D9RenderSystem::setShadingType" );
1726 	}
1727 	//---------------------------------------------------------------------
setLightingEnabled(bool enabled)1728 	void D3D9RenderSystem::setLightingEnabled( bool enabled )
1729 	{
1730 		HRESULT hr;
1731 		if( FAILED( hr = __SetRenderState( D3DRS_LIGHTING, enabled ) ) )
1732 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
1733 			"Failed to set render state D3DRS_LIGHTING", "D3D9RenderSystem::setLightingEnabled" );
1734 	}
1735 	//---------------------------------------------------------------------
setD3D9Light(size_t index,Light * lt)1736 	void D3D9RenderSystem::setD3D9Light( size_t index, Light* lt )
1737 	{
1738 		HRESULT hr;
1739 
1740 		D3DLIGHT9 d3dLight;
1741 		ZeroMemory( &d3dLight, sizeof(d3dLight) );
1742 
1743 		if (!lt)
1744 		{
1745 			if( FAILED( hr = getActiveD3D9Device()->LightEnable( static_cast<DWORD>(index), FALSE) ) )
1746 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
1747 				"Unable to disable light", "D3D9RenderSystem::setD3D9Light" );
1748 		}
1749 		else
1750 		{
1751 			switch( lt->getType() )
1752 			{
1753 			case Light::LT_POINT:
1754 				d3dLight.Type = D3DLIGHT_POINT;
1755 				break;
1756 
1757 			case Light::LT_DIRECTIONAL:
1758 				d3dLight.Type = D3DLIGHT_DIRECTIONAL;
1759 				break;
1760 
1761 			case Light::LT_SPOTLIGHT:
1762 				d3dLight.Type = D3DLIGHT_SPOT;
1763 				d3dLight.Falloff = lt->getSpotlightFalloff();
1764 				d3dLight.Theta = lt->getSpotlightInnerAngle().valueRadians();
1765 				d3dLight.Phi = lt->getSpotlightOuterAngle().valueRadians();
1766 				break;
1767 			}
1768 
1769 			ColourValue col;
1770 			col = lt->getDiffuseColour();
1771 			d3dLight.Diffuse = D3DXCOLOR( col.r, col.g, col.b, col.a );
1772 
1773 			col = lt->getSpecularColour();
1774 			d3dLight.Specular = D3DXCOLOR( col.r, col.g, col.b, col.a );
1775 
1776 			Vector3 vec;
1777 			if( lt->getType() != Light::LT_DIRECTIONAL )
1778 			{
1779 				vec = lt->getDerivedPosition(true);
1780 				d3dLight.Position = D3DXVECTOR3( vec.x, vec.y, vec.z );
1781 			}
1782 			if( lt->getType() != Light::LT_POINT )
1783 			{
1784 				vec = lt->getDerivedDirection();
1785 				d3dLight.Direction = D3DXVECTOR3( vec.x, vec.y, vec.z );
1786 			}
1787 
1788 			d3dLight.Range = lt->getAttenuationRange();
1789 			d3dLight.Attenuation0 = lt->getAttenuationConstant();
1790 			d3dLight.Attenuation1 = lt->getAttenuationLinear();
1791 			d3dLight.Attenuation2 = lt->getAttenuationQuadric();
1792 
1793 			if( FAILED( hr = getActiveD3D9Device()->SetLight( static_cast<DWORD>(index), &d3dLight ) ) )
1794 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set light details", "D3D9RenderSystem::setD3D9Light" );
1795 
1796 			if( FAILED( hr = getActiveD3D9Device()->LightEnable( static_cast<DWORD>(index), TRUE ) ) )
1797 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable light", "D3D9RenderSystem::setD3D9Light" );
1798 		}
1799 
1800 
1801 	}
1802 	//---------------------------------------------------------------------
_setViewMatrix(const Matrix4 & m)1803 	void D3D9RenderSystem::_setViewMatrix( const Matrix4 &m )
1804 	{
1805 		// save latest view matrix
1806 		mViewMatrix = m;
1807 		mViewMatrix[2][0] = -mViewMatrix[2][0];
1808 		mViewMatrix[2][1] = -mViewMatrix[2][1];
1809 		mViewMatrix[2][2] = -mViewMatrix[2][2];
1810 		mViewMatrix[2][3] = -mViewMatrix[2][3];
1811 
1812 		mDxViewMat = D3D9Mappings::makeD3DXMatrix( mViewMatrix );
1813 
1814 		HRESULT hr;
1815 		if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_VIEW, &mDxViewMat ) ) )
1816 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 view matrix", "D3D9RenderSystem::_setViewMatrix" );
1817 
1818 		// also mark clip planes dirty
1819 		if (!mClipPlanes.empty())
1820 			mClipPlanesDirty = true;
1821 	}
1822 	//---------------------------------------------------------------------
_setProjectionMatrix(const Matrix4 & m)1823 	void D3D9RenderSystem::_setProjectionMatrix( const Matrix4 &m )
1824 	{
1825 		// save latest matrix
1826 		mDxProjMat = D3D9Mappings::makeD3DXMatrix( m );
1827 
1828 		if( mActiveRenderTarget->requiresTextureFlipping() )
1829 		{
1830 			// Invert transformed y
1831 			mDxProjMat._12 = - mDxProjMat._12;
1832 			mDxProjMat._22 = - mDxProjMat._22;
1833 			mDxProjMat._32 = - mDxProjMat._32;
1834 			mDxProjMat._42 = - mDxProjMat._42;
1835 		}
1836 
1837 		HRESULT hr;
1838 		if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_PROJECTION, &mDxProjMat ) ) )
1839 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 projection matrix", "D3D9RenderSystem::_setProjectionMatrix" );
1840 
1841 		// also mark clip planes dirty
1842 		if (!mClipPlanes.empty())
1843 			mClipPlanesDirty = true;
1844 
1845 	}
1846 	//---------------------------------------------------------------------
_setWorldMatrix(const Matrix4 & m)1847 	void D3D9RenderSystem::_setWorldMatrix( const Matrix4 &m )
1848 	{
1849 		// save latest matrix
1850 		mDxWorldMat = D3D9Mappings::makeD3DXMatrix( m );
1851 
1852 		HRESULT hr;
1853 		if( FAILED( hr = getActiveD3D9Device()->SetTransform( D3DTS_WORLD, &mDxWorldMat ) ) )
1854 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Cannot set D3D9 world matrix", "D3D9RenderSystem::_setWorldMatrix" );
1855 	}
1856 	//---------------------------------------------------------------------
_setSurfaceParams(const ColourValue & ambient,const ColourValue & diffuse,const ColourValue & specular,const ColourValue & emissive,Real shininess,TrackVertexColourType tracking)1857 	void D3D9RenderSystem::_setSurfaceParams( const ColourValue &ambient, const ColourValue &diffuse,
1858 		const ColourValue &specular, const ColourValue &emissive, Real shininess,
1859 		TrackVertexColourType tracking )
1860 	{
1861 
1862 		D3DMATERIAL9 material;
1863 		material.Diffuse = D3DXCOLOR( diffuse.r, diffuse.g, diffuse.b, diffuse.a );
1864 		material.Ambient = D3DXCOLOR( ambient.r, ambient.g, ambient.b, ambient.a );
1865 		material.Specular = D3DXCOLOR( specular.r, specular.g, specular.b, specular.a );
1866 		material.Emissive = D3DXCOLOR( emissive.r, emissive.g, emissive.b, emissive.a );
1867 		material.Power = shininess;
1868 
1869 		HRESULT hr = getActiveD3D9Device()->SetMaterial( &material );
1870 		if( FAILED( hr ) )
1871 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting D3D material", "D3D9RenderSystem::_setSurfaceParams" );
1872 
1873 
1874 		if(tracking != TVC_NONE)
1875 		{
1876 			__SetRenderState(D3DRS_COLORVERTEX, TRUE);
1877 			__SetRenderState(D3DRS_AMBIENTMATERIALSOURCE, (tracking&TVC_AMBIENT)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1878 			__SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, (tracking&TVC_DIFFUSE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1879 			__SetRenderState(D3DRS_SPECULARMATERIALSOURCE, (tracking&TVC_SPECULAR)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1880 			__SetRenderState(D3DRS_EMISSIVEMATERIALSOURCE, (tracking&TVC_EMISSIVE)?D3DMCS_COLOR1:D3DMCS_MATERIAL);
1881 		}
1882 		else
1883 		{
1884 			__SetRenderState(D3DRS_COLORVERTEX, FALSE);
1885 		}
1886 
1887 	}
1888 	//---------------------------------------------------------------------
_setPointParameters(Real size,bool attenuationEnabled,Real constant,Real linear,Real quadratic,Real minSize,Real maxSize)1889 	void D3D9RenderSystem::_setPointParameters(Real size,
1890 		bool attenuationEnabled, Real constant, Real linear, Real quadratic,
1891 		Real minSize, Real maxSize)
1892 	{
1893 		if(attenuationEnabled)
1894 		{
1895 			// scaling required
1896 			__SetRenderState(D3DRS_POINTSCALEENABLE, TRUE);
1897 			__SetFloatRenderState(D3DRS_POINTSCALE_A, constant);
1898 			__SetFloatRenderState(D3DRS_POINTSCALE_B, linear);
1899 			__SetFloatRenderState(D3DRS_POINTSCALE_C, quadratic);
1900 		}
1901 		else
1902 		{
1903 			// no scaling required
1904 			__SetRenderState(D3DRS_POINTSCALEENABLE, FALSE);
1905 		}
1906 		__SetFloatRenderState(D3DRS_POINTSIZE, size);
1907 		__SetFloatRenderState(D3DRS_POINTSIZE_MIN, minSize);
1908 		if (maxSize == 0.0f)
1909 			maxSize = mCurrentCapabilities->getMaxPointSize();
1910 		__SetFloatRenderState(D3DRS_POINTSIZE_MAX, maxSize);
1911 
1912 
1913 	}
1914 	//---------------------------------------------------------------------
_setPointSpritesEnabled(bool enabled)1915 	void D3D9RenderSystem::_setPointSpritesEnabled(bool enabled)
1916 	{
1917 		if (enabled)
1918 		{
1919 			__SetRenderState(D3DRS_POINTSPRITEENABLE, TRUE);
1920 		}
1921 		else
1922 		{
1923 			__SetRenderState(D3DRS_POINTSPRITEENABLE, FALSE);
1924 		}
1925 	}
1926 	//---------------------------------------------------------------------
_setTexture(size_t stage,bool enabled,const TexturePtr & tex)1927 	void D3D9RenderSystem::_setTexture( size_t stage, bool enabled, const TexturePtr& tex )
1928 	{
1929 		HRESULT hr;
1930 		D3D9TexturePtr dt = tex.staticCast<D3D9Texture>();
1931 		if (enabled && !dt.isNull())
1932 		{
1933 			// note used
1934 			dt->touch();
1935 
1936 			IDirect3DBaseTexture9 *pTex = dt->getTexture();
1937 			if (mTexStageDesc[stage].pTex != pTex)
1938 			{
1939 				hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), pTex);
1940 				if( hr != S_OK )
1941 				{
1942 					String str = "Unable to set texture '" + tex->getName() + "' in D3D9";
1943 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1944 				}
1945 
1946 				// set stage desc.
1947 				mTexStageDesc[stage].pTex = pTex;
1948 				mTexStageDesc[stage].texType = D3D9Mappings::get(dt->getTextureType());
1949 
1950 				// Set gamma now too
1951 				if (dt->isHardwareGammaReadToBeUsed())
1952 				{
1953 					__SetSamplerState(getSamplerId(stage), D3DSAMP_SRGBTEXTURE, TRUE);
1954 				}
1955 				else
1956 				{
1957 					__SetSamplerState(getSamplerId(stage), D3DSAMP_SRGBTEXTURE, FALSE);
1958 				}
1959 			}
1960 		}
1961 		else
1962 		{
1963 			if (mTexStageDesc[stage].pTex != 0)
1964 			{
1965 				hr = getActiveD3D9Device()->SetTexture(static_cast<DWORD>(stage), 0);
1966 				if( hr != S_OK )
1967 				{
1968 					String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9";
1969 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1970 				}
1971 			}
1972 
1973 			hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_COLOROP, D3DTOP_DISABLE);
1974 			if( hr != S_OK )
1975 			{
1976 				String str = "Unable to disable texture '" + StringConverter::toString(stage) + "' in D3D9";
1977 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setTexture" );
1978 			}
1979 
1980 			// set stage desc. to defaults
1981 			mTexStageDesc[stage].pTex = 0;
1982 			mTexStageDesc[stage].autoTexCoordType = TEXCALC_NONE;
1983 			mTexStageDesc[stage].coordIndex = 0;
1984 			mTexStageDesc[stage].texType = D3D9Mappings::D3D_TEX_TYPE_NORMAL;
1985 		}
1986 	}
1987 	//---------------------------------------------------------------------
_setVertexTexture(size_t stage,const TexturePtr & tex)1988 	void D3D9RenderSystem::_setVertexTexture(size_t stage, const TexturePtr& tex)
1989 	{
1990 		if (tex.isNull())
1991 		{
1992 
1993 			if (mTexStageDesc[stage].pVertexTex != 0)
1994 			{
1995 				HRESULT hr = getActiveD3D9Device()->SetTexture(D3DVERTEXTEXTURESAMPLER0 + static_cast<DWORD>(stage), 0);
1996 				if( hr != S_OK )
1997 				{
1998 					String str = "Unable to disable vertex texture '"
1999 						+ StringConverter::toString(stage) + "' in D3D9";
2000 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" );
2001 				}
2002 			}
2003 
2004 			// set stage desc. to defaults
2005 			mTexStageDesc[stage].pVertexTex = 0;
2006 		}
2007 		else
2008 		{
2009 			D3D9TexturePtr dt = tex.staticCast<D3D9Texture>();
2010 			// note used
2011 			dt->touch();
2012 
2013 			IDirect3DBaseTexture9 *pTex = dt->getTexture();
2014 			if (mTexStageDesc[stage].pVertexTex != pTex)
2015 			{
2016 				HRESULT hr = getActiveD3D9Device()->SetTexture(D3DVERTEXTEXTURESAMPLER0 + static_cast<DWORD>(stage), pTex);
2017 				if( hr != S_OK )
2018 				{
2019 					String str = "Unable to set vertex texture '" + tex->getName() + "' in D3D9";
2020 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, str, "D3D9RenderSystem::_setVertexTexture" );
2021 				}
2022 
2023 				// set stage desc.
2024 				mTexStageDesc[stage].pVertexTex = pTex;
2025 			}
2026 
2027 		}
2028 
2029 	}
2030 	//---------------------------------------------------------------------
_disableTextureUnit(size_t texUnit)2031 	void D3D9RenderSystem::_disableTextureUnit(size_t texUnit)
2032 	{
2033 		RenderSystem::_disableTextureUnit(texUnit);
2034 		// also disable vertex texture unit
2035 		static TexturePtr nullPtr;
2036 		_setVertexTexture(texUnit, nullPtr);
2037 	}
2038 	//---------------------------------------------------------------------
_setTextureCoordSet(size_t stage,size_t index)2039 	void D3D9RenderSystem::_setTextureCoordSet( size_t stage, size_t index )
2040 	{
2041 		// if vertex shader is being used, stage and index must match
2042 		if (mVertexProgramBound)
2043 			index = stage;
2044 
2045 		HRESULT hr;
2046 		// Record settings
2047 		mTexStageDesc[stage].coordIndex = index;
2048 
2049         if (mVertexProgramBound)
2050             hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, index );
2051         else
2052 		    hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(mTexStageDesc[stage].autoTexCoordType, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) | index );
2053 		if( FAILED( hr ) )
2054 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. set index", "D3D9RenderSystem::_setTextureCoordSet" );
2055 	}
2056 	//---------------------------------------------------------------------
_setTextureCoordCalculation(size_t stage,TexCoordCalcMethod m,const Frustum * frustum)2057 	void D3D9RenderSystem::_setTextureCoordCalculation( size_t stage, TexCoordCalcMethod m,
2058 		const Frustum* frustum)
2059 	{
2060 		HRESULT hr;
2061 		// record the stage state
2062 		mTexStageDesc[stage].autoTexCoordType = m;
2063 		mTexStageDesc[stage].frustum = frustum;
2064 
2065         if (mVertexProgramBound)
2066             hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, mTexStageDesc[stage].coordIndex );
2067         else
2068 		    hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXCOORDINDEX, D3D9Mappings::get(m, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) | mTexStageDesc[stage].coordIndex );
2069 		if(FAILED(hr))
2070 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture auto tex.coord. generation mode", "D3D9RenderSystem::_setTextureCoordCalculation" );
2071 	}
2072 	//---------------------------------------------------------------------
_setTextureMipmapBias(size_t unit,float bias)2073 	void D3D9RenderSystem::_setTextureMipmapBias(size_t unit, float bias)
2074 	{
2075 		if (mCurrentCapabilities->hasCapability(RSC_MIPMAP_LOD_BIAS))
2076 		{
2077 			// ugh - have to pass float data through DWORD with no conversion
2078 			HRESULT hr = __SetSamplerState(getSamplerId(unit), D3DSAMP_MIPMAPLODBIAS,
2079 				*(DWORD*)&bias);
2080 			if(FAILED(hr))
2081 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture mipmap bias",
2082 				"D3D9RenderSystem::_setTextureMipmapBias" );
2083 
2084 		}
2085 	}
2086 	//---------------------------------------------------------------------
_setTextureMatrix(size_t stage,const Matrix4 & xForm)2087 	void D3D9RenderSystem::_setTextureMatrix( size_t stage, const Matrix4& xForm )
2088 	{
2089 		HRESULT hr;
2090 		D3DXMATRIX d3dMat; // the matrix we'll maybe apply
2091 		Matrix4 newMat = xForm; // the matrix we'll apply after conv. to D3D format
2092 		// Cache texcoord calc method to register
2093 		TexCoordCalcMethod autoTexCoordType = mTexStageDesc[stage].autoTexCoordType;
2094 
2095 		// if a vertex program is bound, we mustn't set texture transforms
2096 		if (mVertexProgramBound)
2097 		{
2098 			hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
2099 			if( FAILED( hr ) )
2100 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable texture coordinate transform", "D3D9RenderSystem::_setTextureMatrix" );
2101 			return;
2102 		}
2103 
2104 
2105 		if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP)
2106 		{
2107 			if (mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().VertexProcessingCaps & D3DVTXPCAPS_TEXGEN_SPHEREMAP)
2108 			{
2109 				/** Invert the texture for the spheremap */
2110 				Matrix4 ogreMatEnvMap = Matrix4::IDENTITY;
2111 				// set env_map values
2112 				ogreMatEnvMap[1][1] = -1.0f;
2113 				// concatenate with the xForm
2114 				newMat = newMat.concatenate(ogreMatEnvMap);
2115 			}
2116 			else
2117 			{
2118 				/* If envmap is applied, but device doesn't support spheremap,
2119 				then we have to use texture transform to make the camera space normal
2120 				reference the envmap properly. This isn't exactly the same as spheremap
2121 				(it looks nasty on flat areas because the camera space normals are the same)
2122 				but it's the best approximation we have in the absence of a proper spheremap */
2123 				// concatenate with the xForm
2124 				newMat = newMat.concatenate(Matrix4::CLIPSPACE2DTOIMAGESPACE);
2125 			}
2126 		}
2127 
2128 		// If this is a cubic reflection, we need to modify using the view matrix
2129 		if (autoTexCoordType == TEXCALC_ENVIRONMENT_MAP_REFLECTION)
2130 		{
2131 			// Get transposed 3x3
2132 			// We want to transpose since that will invert an orthonormal matrix ie rotation
2133 			Matrix4 ogreViewTransposed;
2134 			ogreViewTransposed[0][0] = mViewMatrix[0][0];
2135 			ogreViewTransposed[0][1] = mViewMatrix[1][0];
2136 			ogreViewTransposed[0][2] = mViewMatrix[2][0];
2137 			ogreViewTransposed[0][3] = 0.0f;
2138 
2139 			ogreViewTransposed[1][0] = mViewMatrix[0][1];
2140 			ogreViewTransposed[1][1] = mViewMatrix[1][1];
2141 			ogreViewTransposed[1][2] = mViewMatrix[2][1];
2142 			ogreViewTransposed[1][3] = 0.0f;
2143 
2144 			ogreViewTransposed[2][0] = mViewMatrix[0][2];
2145 			ogreViewTransposed[2][1] = mViewMatrix[1][2];
2146 			ogreViewTransposed[2][2] = mViewMatrix[2][2];
2147 			ogreViewTransposed[2][3] = 0.0f;
2148 
2149 			ogreViewTransposed[3][0] = 0.0f;
2150 			ogreViewTransposed[3][1] = 0.0f;
2151 			ogreViewTransposed[3][2] = 0.0f;
2152 			ogreViewTransposed[3][3] = 1.0f;
2153 
2154 			newMat = newMat.concatenate(ogreViewTransposed);
2155 		}
2156 
2157 		if (autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
2158 		{
2159 			// Derive camera space to projector space transform
2160 			// To do this, we need to undo the camera view matrix, then
2161 			// apply the projector view & projection matrices
2162 			newMat = mViewMatrix.inverse();
2163 			if(mTexProjRelative)
2164 			{
2165 				Matrix4 viewMatrix;
2166 				mTexStageDesc[stage].frustum->calcViewMatrixRelative(mTexProjRelativeOrigin, viewMatrix);
2167 				newMat = viewMatrix * newMat;
2168 			}
2169 			else
2170 			{
2171 				newMat = mTexStageDesc[stage].frustum->getViewMatrix() * newMat;
2172 			}
2173 			newMat = mTexStageDesc[stage].frustum->getProjectionMatrix() * newMat;
2174 			newMat = Matrix4::CLIPSPACE2DTOIMAGESPACE * newMat;
2175 			newMat = xForm * newMat;
2176 		}
2177 
2178 		// need this if texture is a cube map, to invert D3D's z coord
2179 		if (autoTexCoordType != TEXCALC_NONE &&
2180 			autoTexCoordType != TEXCALC_PROJECTIVE_TEXTURE)
2181 		{
2182 			newMat[2][0] = -newMat[2][0];
2183 			newMat[2][1] = -newMat[2][1];
2184 			newMat[2][2] = -newMat[2][2];
2185 			newMat[2][3] = -newMat[2][3];
2186 		}
2187 
2188 		// convert our matrix to D3D format
2189 		d3dMat = D3D9Mappings::makeD3DXMatrix(newMat);
2190 
2191 		// set the matrix if it's not the identity
2192 		if (!D3DXMatrixIsIdentity(&d3dMat))
2193 		{
2194 			/* It's seems D3D automatically add a texture coordinate with value 1,
2195 			and fill up the remaining texture coordinates with 0 for the input
2196 			texture coordinates before pass to texture coordinate transformation.
2197 
2198 			NOTE: It's difference with D3DDECLTYPE enumerated type expand in
2199 			DirectX SDK documentation!
2200 
2201 			So we should prepare the texcoord transform, make the transformation
2202 			just like standardized vector expand, thus, fill w with value 1 and
2203 			others with 0.
2204 			*/
2205 			if (autoTexCoordType == TEXCALC_NONE)
2206 			{
2207 				/* FIXME: The actually input texture coordinate dimensions should
2208 				be determine by texture coordinate vertex element. Now, just trust
2209 				user supplied texture type matches texture coordinate vertex element.
2210 				*/
2211 				if (mTexStageDesc[stage].texType == D3D9Mappings::D3D_TEX_TYPE_NORMAL)
2212 				{
2213 					/* It's 2D input texture coordinate:
2214 
2215 					texcoord in vertex buffer     D3D expanded to     We are adjusted to
2216 					-->                 -->
2217 					(u, v)               (u, v, 1, 0)          (u, v, 0, 1)
2218 					*/
2219 					std::swap(d3dMat._31, d3dMat._41);
2220 					std::swap(d3dMat._32, d3dMat._42);
2221 					std::swap(d3dMat._33, d3dMat._43);
2222 					std::swap(d3dMat._34, d3dMat._44);
2223 				}
2224 			}
2225 			else
2226 			{
2227 				// All texgen generate 3D input texture coordinates.
2228 			}
2229 
2230 			// tell D3D the dimension of tex. coord.
2231 			int texCoordDim = D3DTTFF_COUNT2;
2232 			if (mTexStageDesc[stage].autoTexCoordType == TEXCALC_PROJECTIVE_TEXTURE)
2233 			{
2234 				/* We want texcoords (u, v, w, q) always get divided by q, but D3D
2235 				projected texcoords is divided by the last element (in the case of
2236 				2D texcoord, is w). So we tweak the transform matrix, transform the
2237 				texcoords with w and q swapped: (u, v, q, w), and then D3D will
2238 				divide u, v by q. The w and q just ignored as it wasn't used by
2239 				rasterizer.
2240 				*/
2241 				switch (mTexStageDesc[stage].texType)
2242 				{
2243 				case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
2244 					std::swap(d3dMat._13, d3dMat._14);
2245 					std::swap(d3dMat._23, d3dMat._24);
2246 					std::swap(d3dMat._33, d3dMat._34);
2247 					std::swap(d3dMat._43, d3dMat._44);
2248 
2249 					texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT3;
2250 					break;
2251 
2252 				case D3D9Mappings::D3D_TEX_TYPE_CUBE:
2253 				case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
2254 					// Yes, we support 3D projective texture.
2255 					texCoordDim = D3DTTFF_PROJECTED | D3DTTFF_COUNT4;
2256 					break;
2257 				}
2258 			}
2259 			else
2260 			{
2261 				switch (mTexStageDesc[stage].texType)
2262 				{
2263 				case D3D9Mappings::D3D_TEX_TYPE_NORMAL:
2264 					texCoordDim = D3DTTFF_COUNT2;
2265 					break;
2266 				case D3D9Mappings::D3D_TEX_TYPE_CUBE:
2267 				case D3D9Mappings::D3D_TEX_TYPE_VOLUME:
2268 					texCoordDim = D3DTTFF_COUNT3;
2269 					break;
2270 				}
2271 			}
2272 
2273 			hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, texCoordDim );
2274 			if (FAILED(hr))
2275 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture coord. dimension", "D3D9RenderSystem::_setTextureMatrix" );
2276 
2277 			hr = getActiveD3D9Device()->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + stage), &d3dMat );
2278 			if (FAILED(hr))
2279 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set texture matrix", "D3D9RenderSystem::_setTextureMatrix" );
2280 		}
2281 		else
2282 		{
2283 			// disable all of this
2284 			hr = __SetTextureStageState( static_cast<DWORD>(stage), D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );
2285 			if( FAILED( hr ) )
2286 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable texture coordinate transform", "D3D9RenderSystem::_setTextureMatrix" );
2287 
2288 			// Needless to sets texture transform here, it's never used at all
2289 		}
2290 	}
2291 	//---------------------------------------------------------------------
_setTextureAddressingMode(size_t stage,const TextureUnitState::UVWAddressingMode & uvw)2292 	void D3D9RenderSystem::_setTextureAddressingMode( size_t stage,
2293 		const TextureUnitState::UVWAddressingMode& uvw )
2294 	{
2295 		HRESULT hr;
2296 		if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSU, D3D9Mappings::get(uvw.u, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
2297 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for U", "D3D9RenderSystem::_setTextureAddressingMode" );
2298 		if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSV, D3D9Mappings::get(uvw.v, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
2299 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for V", "D3D9RenderSystem::_setTextureAddressingMode" );
2300 		if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_ADDRESSW, D3D9Mappings::get(uvw.w, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) ) ) )
2301 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture addressing mode for W", "D3D9RenderSystem::_setTextureAddressingMode" );
2302 	}
2303 	//-----------------------------------------------------------------------------
_setTextureBorderColour(size_t stage,const ColourValue & colour)2304 	void D3D9RenderSystem::_setTextureBorderColour(size_t stage,
2305 		const ColourValue& colour)
2306 	{
2307 		HRESULT hr;
2308 		if( FAILED( hr = __SetSamplerState( getSamplerId(stage), D3DSAMP_BORDERCOLOR, colour.getAsARGB()) ) )
2309 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture border colour", "D3D9RenderSystem::_setTextureBorderColour" );
2310 	}
2311 	//---------------------------------------------------------------------
_setTextureBlendMode(size_t stage,const LayerBlendModeEx & bm)2312 	void D3D9RenderSystem::_setTextureBlendMode( size_t stage, const LayerBlendModeEx& bm )
2313 	{
2314 		HRESULT hr = S_OK;
2315 		D3DTEXTURESTAGESTATETYPE tss;
2316 		D3DCOLOR manualD3D;
2317 
2318 		// choose type of blend.
2319 		if( bm.blendType == LBT_COLOUR )
2320 			tss = D3DTSS_COLOROP;
2321 		else if( bm.blendType == LBT_ALPHA )
2322 			tss = D3DTSS_ALPHAOP;
2323 		else
2324 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
2325 			"Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
2326 
2327 		// set manual factor if required by operation
2328 		if (bm.operation == LBX_BLEND_MANUAL)
2329 		{
2330 			hr = __SetRenderState( D3DRS_TEXTUREFACTOR, D3DXCOLOR(0.0, 0.0, 0.0,  bm.factor) );
2331 			if (FAILED(hr))
2332 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
2333 		}
2334 		// set operation
2335 		hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.operation, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps()) );
2336 		if (FAILED(hr))
2337 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set operation", "D3D9RenderSystem::_setTextureBlendMode" );
2338 
2339 		// choose source 1
2340 		if( bm.blendType == LBT_COLOUR )
2341 		{
2342 			tss = D3DTSS_COLORARG1;
2343 			manualD3D = D3DXCOLOR( bm.colourArg1.r, bm.colourArg1.g, bm.colourArg1.b, bm.colourArg1.a );
2344 			mManualBlendColours[stage][0] = bm.colourArg1;
2345 		}
2346 		else if( bm.blendType == LBT_ALPHA )
2347 		{
2348 			tss = D3DTSS_ALPHAARG1;
2349 			manualD3D = D3DXCOLOR( mManualBlendColours[stage][0].r,
2350 				mManualBlendColours[stage][0].g,
2351 				mManualBlendColours[stage][0].b, bm.alphaArg1 );
2352 		}
2353 		else
2354 		{
2355 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
2356 				"Invalid blend type", "D3D9RenderSystem::_setTextureBlendMode");
2357 		}
2358 		// Set manual factor if required
2359 		if (bm.source1 == LBS_MANUAL)
2360 		{
2361 			if (mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT))
2362 			{
2363 				// Per-stage state
2364 				hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_CONSTANT, manualD3D);
2365 			}
2366 			else
2367 			{
2368 				// Global state
2369 				hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
2370 			}
2371 			if (FAILED(hr))
2372 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
2373 		}
2374 		// set source 1
2375 		hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.source1, mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) );
2376 		if (FAILED(hr))
2377 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source1", "D3D9RenderSystem::_setTextureBlendMode" );
2378 
2379 		// choose source 2
2380 		if( bm.blendType == LBT_COLOUR )
2381 		{
2382 			tss = D3DTSS_COLORARG2;
2383 			manualD3D = D3DXCOLOR( bm.colourArg2.r, bm.colourArg2.g, bm.colourArg2.b, bm.colourArg2.a );
2384 			mManualBlendColours[stage][1] = bm.colourArg2;
2385 		}
2386 		else if( bm.blendType == LBT_ALPHA )
2387 		{
2388 			tss = D3DTSS_ALPHAARG2;
2389 			manualD3D = D3DXCOLOR( mManualBlendColours[stage][1].r,
2390 				mManualBlendColours[stage][1].g,
2391 				mManualBlendColours[stage][1].b,
2392 				bm.alphaArg2 );
2393 		}
2394 		// Set manual factor if required
2395 		if (bm.source2 == LBS_MANUAL)
2396 		{
2397 			if (mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT))
2398 			{
2399 				// Per-stage state
2400 				hr = __SetTextureStageState(static_cast<DWORD>(stage), D3DTSS_CONSTANT, manualD3D);
2401 			}
2402 			else
2403 			{
2404 				hr = __SetRenderState( D3DRS_TEXTUREFACTOR, manualD3D );
2405 			}
2406 			if (FAILED(hr))
2407 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set manual factor", "D3D9RenderSystem::_setTextureBlendMode" );
2408 		}
2409 		// Now set source 2
2410 		hr = __SetTextureStageState( static_cast<DWORD>(stage), tss, D3D9Mappings::get(bm.source2, mCurrentCapabilities->hasCapability(RSC_PERSTAGECONSTANT)) );
2411 		if (FAILED(hr))
2412 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source 2", "D3D9RenderSystem::_setTextureBlendMode" );
2413 
2414 		// Set interpolation factor if lerping
2415 		if (bm.operation == LBX_BLEND_DIFFUSE_COLOUR &&
2416 			mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().TextureOpCaps & D3DTEXOPCAPS_LERP)
2417 		{
2418 			// choose source 0 (lerp factor)
2419 			if( bm.blendType == LBT_COLOUR )
2420 			{
2421 				tss = D3DTSS_COLORARG0;
2422 			}
2423 			else if( bm.blendType == LBT_ALPHA )
2424 			{
2425 				tss = D3DTSS_ALPHAARG0;
2426 			}
2427 			hr = __SetTextureStageState(static_cast<DWORD>(stage), tss, D3DTA_DIFFUSE);
2428 
2429 			if (FAILED(hr))
2430 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set lerp source 0",
2431 				"D3D9RenderSystem::_setTextureBlendMode" );
2432 
2433 		}
2434 	}
2435 	//---------------------------------------------------------------------
_setSceneBlending(SceneBlendFactor sourceFactor,SceneBlendFactor destFactor,SceneBlendOperation op)2436 	void D3D9RenderSystem::_setSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendOperation op )
2437 	{
2438 		HRESULT hr;
2439 		if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO)
2440 		{
2441 			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
2442 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2443 		}
2444 		else
2445 		{
2446 			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
2447 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2448 			if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE)))
2449 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set separate alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2450 			if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
2451 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source blend", "D3D9RenderSystem::_setSceneBlending" );
2452 			if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
2453 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set destination blend", "D3D9RenderSystem::_setSceneBlending" );
2454 		}
2455 
2456 		if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op))))
2457 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" );
2458 		if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(op))))
2459 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" );
2460 	}
2461 	//---------------------------------------------------------------------
_setSeparateSceneBlending(SceneBlendFactor sourceFactor,SceneBlendFactor destFactor,SceneBlendFactor sourceFactorAlpha,SceneBlendFactor destFactorAlpha,SceneBlendOperation op,SceneBlendOperation alphaOp)2462 	void D3D9RenderSystem::_setSeparateSceneBlending( SceneBlendFactor sourceFactor, SceneBlendFactor destFactor, SceneBlendFactor sourceFactorAlpha,
2463 		SceneBlendFactor destFactorAlpha, SceneBlendOperation op, SceneBlendOperation alphaOp )
2464 	{
2465 		HRESULT hr;
2466 		if( sourceFactor == SBF_ONE && destFactor == SBF_ZERO &&
2467 			sourceFactorAlpha == SBF_ONE && destFactorAlpha == SBF_ZERO)
2468 		{
2469 			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE)))
2470 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSceneBlending" );
2471 		}
2472 		else
2473 		{
2474 			if (FAILED(hr = __SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE)))
2475 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha blending option", "D3D9RenderSystem::_setSeperateSceneBlending" );
2476 			if (FAILED(hr = __SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE)))
2477 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set separate alpha blending option", "D3D9RenderSystem::_setSeperateSceneBlending" );
2478 			if( FAILED( hr = __SetRenderState( D3DRS_SRCBLEND, D3D9Mappings::get(sourceFactor) ) ) )
2479 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set source blend", "D3D9RenderSystem::_setSeperateSceneBlending" );
2480 			if( FAILED( hr = __SetRenderState( D3DRS_DESTBLEND, D3D9Mappings::get(destFactor) ) ) )
2481 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set destination blend", "D3D9RenderSystem::_setSeperateSceneBlending" );
2482 			if( FAILED( hr = __SetRenderState( D3DRS_SRCBLENDALPHA, D3D9Mappings::get(sourceFactorAlpha) ) ) )
2483 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha source blend", "D3D9RenderSystem::_setSeperateSceneBlending" );
2484 			if( FAILED( hr = __SetRenderState( D3DRS_DESTBLENDALPHA, D3D9Mappings::get(destFactorAlpha) ) ) )
2485 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha destination blend", "D3D9RenderSystem::_setSeperateSceneBlending" );
2486 		}
2487 
2488 		if (FAILED(hr = __SetRenderState(D3DRS_BLENDOP, D3D9Mappings::get(op))))
2489 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" );
2490 		if (FAILED(hr = __SetRenderState(D3DRS_BLENDOPALPHA, D3D9Mappings::get(alphaOp))))
2491 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha scene blending operation option", "D3D9RenderSystem::_setSceneBlendingOperation" );
2492 	}
2493 	//---------------------------------------------------------------------
_setAlphaRejectSettings(CompareFunction func,unsigned char value,bool alphaToCoverage)2494 	void D3D9RenderSystem::_setAlphaRejectSettings( CompareFunction func, unsigned char value, bool alphaToCoverage )
2495 	{
2496 		HRESULT hr;
2497 		bool a2c = false;
2498 		static bool lasta2c = false;
2499 
2500 		if (func != CMPF_ALWAYS_PASS)
2501 		{
2502 			if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE ) ) )
2503 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to enable alpha testing",
2504 				"D3D9RenderSystem::_setAlphaRejectSettings" );
2505 
2506 			a2c = alphaToCoverage;
2507 		}
2508 		else
2509 		{
2510 			if( FAILED( hr = __SetRenderState( D3DRS_ALPHATESTENABLE,  FALSE ) ) )
2511 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to disable alpha testing",
2512 				"D3D9RenderSystem::_setAlphaRejectSettings" );
2513 		}
2514 		// Set always just be sure
2515 		if( FAILED( hr = __SetRenderState( D3DRS_ALPHAFUNC, D3D9Mappings::get(func) ) ) )
2516 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha reject function", "D3D9RenderSystem::_setAlphaRejectSettings" );
2517 		if( FAILED( hr = __SetRenderState( D3DRS_ALPHAREF, value ) ) )
2518 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set render state D3DRS_ALPHAREF", "D3D9RenderSystem::_setAlphaRejectSettings" );
2519 
2520 		// Alpha to coverage
2521 		if (getCapabilities()->hasCapability(RSC_ALPHA_TO_COVERAGE))
2522 		{
2523 			// Vendor-specific hacks on renderstate, gotta love 'em
2524 			if (getCapabilities()->getVendor() == GPU_NVIDIA)
2525 			{
2526 				if (a2c)
2527 				{
2528 					if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y,  (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C') ) ) )
2529 						OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" );
2530 				}
2531 				else
2532 				{
2533 					if( FAILED( hr = __SetRenderState( D3DRS_ADAPTIVETESS_Y,  D3DFMT_UNKNOWN ) ) )
2534 						OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" );
2535 				}
2536 
2537 			}
2538 			else if ((getCapabilities()->getVendor() == GPU_AMD))
2539 			{
2540 				if (a2c)
2541 				{
2542 					if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE,  MAKEFOURCC('A','2','M','1') ) ) )
2543 						OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" );
2544 				}
2545 				else
2546 				{
2547 					// discovered this through trial and error, seems to work
2548 					if( FAILED( hr = __SetRenderState( D3DRS_POINTSIZE,  MAKEFOURCC('A','2','M','0') ) ) )
2549 						OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set alpha to coverage option", "D3D9RenderSystem::_setAlphaRejectSettings" );
2550 				}
2551 			}
2552 			// no hacks available for any other vendors?
2553 			lasta2c = a2c;
2554 		}
2555 
2556 	}
2557 	//---------------------------------------------------------------------
_setCullingMode(CullingMode mode)2558 	void D3D9RenderSystem::_setCullingMode( CullingMode mode )
2559 	{
2560 		mCullingMode = mode;
2561 		HRESULT hr;
2562 		bool flip = ((mActiveRenderTarget->requiresTextureFlipping() && !mInvertVertexWinding) ||
2563 			(!mActiveRenderTarget->requiresTextureFlipping() && mInvertVertexWinding));
2564 
2565 		if( FAILED (hr = __SetRenderState(D3DRS_CULLMODE,
2566 			D3D9Mappings::get(mode, flip))) )
2567 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set culling mode", "D3D9RenderSystem::_setCullingMode" );
2568 	}
2569 	//---------------------------------------------------------------------
_setDepthBufferParams(bool depthTest,bool depthWrite,CompareFunction depthFunction)2570 	void D3D9RenderSystem::_setDepthBufferParams( bool depthTest, bool depthWrite, CompareFunction depthFunction )
2571 	{
2572 		_setDepthBufferCheckEnabled( depthTest );
2573 		_setDepthBufferWriteEnabled( depthWrite );
2574 		_setDepthBufferFunction( depthFunction );
2575 	}
2576 	//---------------------------------------------------------------------
_setDepthBufferCheckEnabled(bool enabled)2577 	void D3D9RenderSystem::_setDepthBufferCheckEnabled( bool enabled )
2578 	{
2579 		HRESULT hr;
2580 
2581 		if( enabled )
2582 		{
2583 			// Use w-buffer if available and enabled
2584 			if( mWBuffer && mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_WBUFFER )
2585 				hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_USEW );
2586 			else
2587 				hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_TRUE );
2588 		}
2589 		else
2590 			hr = __SetRenderState( D3DRS_ZENABLE, D3DZB_FALSE );
2591 
2592 		if( FAILED( hr ) )
2593 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test state", "D3D9RenderSystem::_setDepthBufferCheckEnabled" );
2594 	}
2595 	//---------------------------------------------------------------------
_setDepthBufferWriteEnabled(bool enabled)2596 	void D3D9RenderSystem::_setDepthBufferWriteEnabled( bool enabled )
2597 	{
2598 		HRESULT hr;
2599 
2600 		if( FAILED( hr = __SetRenderState( D3DRS_ZWRITEENABLE, enabled ) ) )
2601 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer write state", "D3D9RenderSystem::_setDepthBufferWriteEnabled" );
2602 	}
2603 	//---------------------------------------------------------------------
_setDepthBufferFunction(CompareFunction func)2604 	void D3D9RenderSystem::_setDepthBufferFunction( CompareFunction func )
2605 	{
2606 		HRESULT hr;
2607 		if( FAILED( hr = __SetRenderState( D3DRS_ZFUNC, D3D9Mappings::get(func) ) ) )
2608 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting depth buffer test function", "D3D9RenderSystem::_setDepthBufferFunction" );
2609 	}
2610 	//---------------------------------------------------------------------
_setDepthBias(float constantBias,float slopeScaleBias)2611 	void D3D9RenderSystem::_setDepthBias(float constantBias, float slopeScaleBias)
2612 	{
2613 
2614 		if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_DEPTHBIAS) != 0)
2615 		{
2616 			// Negate bias since D3D is backward
2617 			// D3D also expresses the constant bias as an absolute value, rather than
2618 			// relative to minimum depth unit, so scale to fit
2619 			constantBias = -constantBias / 250000.0f;
2620 			HRESULT hr = __SetRenderState(D3DRS_DEPTHBIAS, FLOAT2DWORD(constantBias));
2621 			if (FAILED(hr))
2622 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting constant depth bias",
2623 				"D3D9RenderSystem::_setDepthBias");
2624 		}
2625 
2626 		if ((mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_SLOPESCALEDEPTHBIAS) != 0)
2627 		{
2628 			// Negate bias since D3D is backward
2629 			slopeScaleBias = -slopeScaleBias;
2630 			HRESULT hr = __SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, FLOAT2DWORD(slopeScaleBias));
2631 			if (FAILED(hr))
2632 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting slope scale depth bias",
2633 				"D3D9RenderSystem::_setDepthBias");
2634 		}
2635 
2636 
2637 	}
2638 	//---------------------------------------------------------------------
_setColourBufferWriteEnabled(bool red,bool green,bool blue,bool alpha)2639 	void D3D9RenderSystem::_setColourBufferWriteEnabled(bool red, bool green,
2640 		bool blue, bool alpha)
2641 	{
2642 		DWORD val = 0;
2643 		if (red)
2644 			val |= D3DCOLORWRITEENABLE_RED;
2645 		if (green)
2646 			val |= D3DCOLORWRITEENABLE_GREEN;
2647 		if (blue)
2648 			val |= D3DCOLORWRITEENABLE_BLUE;
2649 		if (alpha)
2650 			val |= D3DCOLORWRITEENABLE_ALPHA;
2651 		HRESULT hr = __SetRenderState(D3DRS_COLORWRITEENABLE, val);
2652 		if (FAILED(hr))
2653 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting colour write enable flags",
2654 			"D3D9RenderSystem::_setColourBufferWriteEnabled");
2655 	}
2656 	//---------------------------------------------------------------------
_setFog(FogMode mode,const ColourValue & colour,Real densitiy,Real start,Real end)2657 	void D3D9RenderSystem::_setFog( FogMode mode, const ColourValue& colour, Real densitiy, Real start, Real end )
2658 	{
2659 		HRESULT hr;
2660 
2661 		D3DRENDERSTATETYPE fogType, fogTypeNot;
2662 
2663 		if (mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().RasterCaps & D3DPRASTERCAPS_FOGTABLE)
2664 		{
2665 			fogType = D3DRS_FOGTABLEMODE;
2666 			fogTypeNot = D3DRS_FOGVERTEXMODE;
2667 		}
2668 		else
2669 		{
2670 			fogType = D3DRS_FOGVERTEXMODE;
2671 			fogTypeNot = D3DRS_FOGTABLEMODE;
2672 		}
2673 
2674 		if( mode == FOG_NONE)
2675 		{
2676 			// just disable
2677 			hr = __SetRenderState(fogType, D3DFOG_NONE );
2678 			hr = __SetRenderState(D3DRS_FOGENABLE, FALSE);
2679 		}
2680 		else
2681 		{
2682 			// Allow fog
2683 			hr = __SetRenderState( D3DRS_FOGENABLE, TRUE );
2684 			hr = __SetRenderState( fogTypeNot, D3DFOG_NONE );
2685 			hr = __SetRenderState( fogType, D3D9Mappings::get(mode) );
2686 
2687 			hr = __SetRenderState( D3DRS_FOGCOLOR, colour.getAsARGB() );
2688 			hr = __SetFloatRenderState( D3DRS_FOGSTART, start );
2689 			hr = __SetFloatRenderState( D3DRS_FOGEND, end );
2690 			hr = __SetFloatRenderState( D3DRS_FOGDENSITY, densitiy );
2691 		}
2692 
2693 		if( FAILED( hr ) )
2694 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting render state", "D3D9RenderSystem::_setFog" );
2695 	}
2696 	//---------------------------------------------------------------------
_setPolygonMode(PolygonMode level)2697 	void D3D9RenderSystem::_setPolygonMode(PolygonMode level)
2698 	{
2699 		HRESULT hr = __SetRenderState(D3DRS_FILLMODE, D3D9Mappings::get(level));
2700 		if (FAILED(hr))
2701 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting polygon mode.", "D3D9RenderSystem::setPolygonMode");
2702 	}
2703 	//---------------------------------------------------------------------
setStencilCheckEnabled(bool enabled)2704 	void D3D9RenderSystem::setStencilCheckEnabled(bool enabled)
2705 	{
2706 		// Allow stencilling
2707 		HRESULT hr = __SetRenderState(D3DRS_STENCILENABLE, enabled);
2708 		if (FAILED(hr))
2709 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error enabling / disabling stencilling.",
2710 			"D3D9RenderSystem::setStencilCheckEnabled");
2711 	}
2712 	//---------------------------------------------------------------------
setStencilBufferParams(CompareFunction func,uint32 refValue,uint32 compareMask,uint32 writeMask,StencilOperation stencilFailOp,StencilOperation depthFailOp,StencilOperation passOp,bool twoSidedOperation)2713 	void D3D9RenderSystem::setStencilBufferParams(CompareFunction func,
2714 		uint32 refValue, uint32 compareMask, uint32 writeMask, StencilOperation stencilFailOp,
2715 		StencilOperation depthFailOp, StencilOperation passOp,
2716 		bool twoSidedOperation)
2717 	{
2718 		HRESULT hr;
2719 		bool flip;
2720 
2721 		// 2-sided operation
2722 		if (twoSidedOperation)
2723 		{
2724 			if (!mCurrentCapabilities->hasCapability(RSC_TWO_SIDED_STENCIL))
2725 				OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "2-sided stencils are not supported",
2726 				"D3D9RenderSystem::setStencilBufferParams");
2727 			hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE);
2728 			if (FAILED(hr))
2729 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 2-sided stencil mode.",
2730 				"D3D9RenderSystem::setStencilBufferParams");
2731 			// NB: We should always treat CCW as front face for consistent with default
2732 			// culling mode. Therefore, we must take care with two-sided stencil settings.
2733 			flip = (mInvertVertexWinding && mActiveRenderTarget->requiresTextureFlipping()) ||
2734 				(!mInvertVertexWinding && !mActiveRenderTarget->requiresTextureFlipping());
2735 
2736 			// Set alternative versions of ops
2737 			// fail op
2738 			hr = __SetRenderState(D3DRS_CCW_STENCILFAIL, D3D9Mappings::get(stencilFailOp, !flip));
2739 			if (FAILED(hr))
2740 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation (2-sided).",
2741 				"D3D9RenderSystem::setStencilBufferParams");
2742 
2743 			// depth fail op
2744 			hr = __SetRenderState(D3DRS_CCW_STENCILZFAIL, D3D9Mappings::get(depthFailOp, !flip));
2745 			if (FAILED(hr))
2746 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation (2-sided).",
2747 				"D3D9RenderSystem::setStencilBufferParams");
2748 
2749 			// pass op
2750 			hr = __SetRenderState(D3DRS_CCW_STENCILPASS, D3D9Mappings::get(passOp, !flip));
2751 			if (FAILED(hr))
2752 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation (2-sided).",
2753 				"D3D9RenderSystem::setStencilBufferParams");
2754 		}
2755 		else
2756 		{
2757 			hr = __SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE);
2758 			if (FAILED(hr))
2759 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting 1-sided stencil mode.",
2760 				"D3D9RenderSystem::setStencilBufferParams");
2761 			flip = false;
2762 		}
2763 
2764 		// func
2765 		hr = __SetRenderState(D3DRS_STENCILFUNC, D3D9Mappings::get(func));
2766 		if (FAILED(hr))
2767 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer test function.",
2768 			"D3D9RenderSystem::setStencilBufferParams");
2769 
2770 		// reference value
2771 		hr = __SetRenderState(D3DRS_STENCILREF, refValue);
2772 		if (FAILED(hr))
2773 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer reference value.",
2774 			"D3D9RenderSystem::setStencilBufferParams");
2775 
2776 		// compare mask
2777 		hr = __SetRenderState(D3DRS_STENCILMASK, compareMask);
2778 		if (FAILED(hr))
2779 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer compare mask.",
2780 			"D3D9RenderSystem::setStencilBufferParams");
2781 
2782 		// compare mask
2783 		hr = __SetRenderState(D3DRS_STENCILWRITEMASK, writeMask);
2784 		if (FAILED(hr))
2785 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil buffer write mask.",
2786 			"D3D9RenderSystem::setStencilBufferParams");
2787 
2788 		// fail op
2789 		hr = __SetRenderState(D3DRS_STENCILFAIL, D3D9Mappings::get(stencilFailOp, flip));
2790 		if (FAILED(hr))
2791 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil fail operation.",
2792 			"D3D9RenderSystem::setStencilBufferParams");
2793 
2794 		// depth fail op
2795 		hr = __SetRenderState(D3DRS_STENCILZFAIL, D3D9Mappings::get(depthFailOp, flip));
2796 		if (FAILED(hr))
2797 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil depth fail operation.",
2798 			"D3D9RenderSystem::setStencilBufferParams");
2799 
2800 		// pass op
2801 		hr = __SetRenderState(D3DRS_STENCILPASS, D3D9Mappings::get(passOp, flip));
2802 		if (FAILED(hr))
2803 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error setting stencil pass operation.",
2804 			"D3D9RenderSystem::setStencilBufferParams");
2805 	}
2806 	//---------------------------------------------------------------------
_setTextureUnitFiltering(size_t unit,FilterType ftype,FilterOptions filter)2807 	void D3D9RenderSystem::_setTextureUnitFiltering(size_t unit, FilterType ftype,
2808 		FilterOptions filter)
2809 	{
2810 		HRESULT hr;
2811 		D3D9Mappings::eD3DTexType texType = mTexStageDesc[unit].texType;
2812 		hr = __SetSamplerState( getSamplerId(unit), D3D9Mappings::get(ftype),
2813 			D3D9Mappings::get(ftype, filter, mDeviceManager->getActiveDevice()->getD3D9DeviceCaps(), texType));
2814 		if (FAILED(hr))
2815 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set texture filter ", "D3D9RenderSystem::_setTextureUnitFiltering");
2816 	}
2817 	//---------------------------------------------------------------------
_setTextureUnitCompareFunction(size_t unit,CompareFunction function)2818 	void D3D9RenderSystem::_setTextureUnitCompareFunction(size_t unit, CompareFunction function)
2819 	{
2820 		//no effect in directX9 rendersystem
2821 	}
2822 	//---------------------------------------------------------------------
_setTextureUnitCompareEnabled(size_t unit,bool compare)2823 	void D3D9RenderSystem::_setTextureUnitCompareEnabled(size_t unit, bool compare)
2824 	{
2825 		//no effect in directX9 rendersystem
2826 	}
2827 	//---------------------------------------------------------------------
_getCurrentAnisotropy(size_t unit)2828 	DWORD D3D9RenderSystem::_getCurrentAnisotropy(size_t unit)
2829 	{
2830 		DWORD oldVal;
2831 		getActiveD3D9Device()->GetSamplerState(static_cast<DWORD>(unit), D3DSAMP_MAXANISOTROPY, &oldVal);
2832 		return oldVal;
2833 	}
2834 	//---------------------------------------------------------------------
_setTextureLayerAnisotropy(size_t unit,unsigned int maxAnisotropy)2835 	void D3D9RenderSystem::_setTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy)
2836 	{
2837 		if (static_cast<DWORD>(maxAnisotropy) > mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy)
2838 			maxAnisotropy = mDeviceManager->getActiveDevice()->getD3D9DeviceCaps().MaxAnisotropy;
2839 
2840 		if (_getCurrentAnisotropy(unit) != maxAnisotropy)
2841 			__SetSamplerState( getSamplerId(unit), D3DSAMP_MAXANISOTROPY, maxAnisotropy );
2842 	}
2843 	//---------------------------------------------------------------------
__SetRenderState(D3DRENDERSTATETYPE state,DWORD value)2844 	HRESULT D3D9RenderSystem::__SetRenderState(D3DRENDERSTATETYPE state, DWORD value)
2845 	{
2846 		HRESULT hr;
2847 		DWORD oldVal;
2848 
2849 		if ( FAILED( hr = getActiveD3D9Device()->GetRenderState(state, &oldVal) ) )
2850 			return hr;
2851 		if ( oldVal == value )
2852 			return D3D_OK;
2853 		else
2854 			return getActiveD3D9Device()->SetRenderState(state, value);
2855 	}
2856 	//---------------------------------------------------------------------
__SetSamplerState(DWORD sampler,D3DSAMPLERSTATETYPE type,DWORD value)2857 	HRESULT D3D9RenderSystem::__SetSamplerState(DWORD sampler, D3DSAMPLERSTATETYPE type, DWORD value)
2858 	{
2859 		HRESULT hr;
2860 		DWORD oldVal;
2861 
2862 		if ( FAILED( hr = getActiveD3D9Device()->GetSamplerState(sampler, type, &oldVal) ) )
2863 			return hr;
2864 		if ( oldVal == value )
2865 			return D3D_OK;
2866 		else
2867 			return getActiveD3D9Device()->SetSamplerState(sampler, type, value);
2868 	}
2869 	//---------------------------------------------------------------------
__SetTextureStageState(DWORD stage,D3DTEXTURESTAGESTATETYPE type,DWORD value)2870 	HRESULT D3D9RenderSystem::__SetTextureStageState(DWORD stage, D3DTEXTURESTAGESTATETYPE type, DWORD value)
2871 	{
2872 		HRESULT hr;
2873 		DWORD oldVal;
2874 
2875 		// can only set fixed-function texture stage state
2876 		if (stage < 8)
2877 		{
2878 			if ( FAILED( hr = getActiveD3D9Device()->GetTextureStageState(stage, type, &oldVal) ) )
2879 				return hr;
2880 			if ( oldVal == value )
2881 				return D3D_OK;
2882 			else
2883 				return getActiveD3D9Device()->SetTextureStageState(stage, type, value);
2884 		}
2885 		else
2886 		{
2887 			return D3D_OK;
2888 		}
2889 	}
2890 	//---------------------------------------------------------------------
_createDepthBufferFor(RenderTarget * renderTarget)2891 	DepthBuffer* D3D9RenderSystem::_createDepthBufferFor( RenderTarget *renderTarget )
2892 	{
2893 		IDirect3DSurface9* pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS];
2894 		memset (pBack, 0, sizeof(pBack) );
2895 		renderTarget->getCustomAttribute( "DDBACKBUFFER", &pBack );
2896 		if( !pBack[0] )
2897 			return 0;
2898 
2899 		D3DSURFACE_DESC srfDesc;
2900 		if( FAILED(pBack[0]->GetDesc(&srfDesc)) )
2901 		{
2902 			OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
2903 					 "Failed to retrieve Surface Description from BackBuffer. RenderTarget: " +
2904 																			renderTarget->getName(),
2905 					 "D3D9RenderSystem::_createDepthBufferFor" );
2906 		}
2907 
2908 		//Find an appropiarte format for this depth buffer that best matches the RenderTarget's
2909 		D3DFORMAT dsfmt = _getDepthStencilFormatFor( srfDesc.Format );
2910 
2911 		//Create the depthstencil surface
2912 		IDirect3DSurface9 *depthBufferSurface = NULL;
2913 		IDirect3DDevice9* activeDevice = getActiveD3D9Device();
2914 		HRESULT hr = activeDevice->CreateDepthStencilSurface(
2915 											srfDesc.Width, srfDesc.Height, dsfmt,
2916 											srfDesc.MultiSampleType, srfDesc.MultiSampleQuality,
2917 											TRUE,  // discard true or false?
2918 											&depthBufferSurface, NULL);
2919 		if( FAILED(hr) )
2920 		{
2921 			String msg = DXGetErrorDescription(hr);
2922 			OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
2923 						"Error CreateDepthStencilSurface : " + msg,
2924 						"D3D9RenderSystem::_createDepthBufferFor" );
2925 		}
2926 
2927 		D3D9DepthBuffer *newDepthBuffer = OGRE_NEW D3D9DepthBuffer( DepthBuffer::POOL_DEFAULT, this,
2928 												activeDevice, depthBufferSurface,
2929 												dsfmt, srfDesc.Width, srfDesc.Height,
2930 												srfDesc.MultiSampleType, srfDesc.MultiSampleQuality, false );
2931 
2932 		return newDepthBuffer;
2933 	}
2934 
2935 	//---------------------------------------------------------------------
_addManualDepthBuffer(IDirect3DDevice9 * depthSurfaceDevice,IDirect3DSurface9 * depthSurface)2936 	DepthBuffer* D3D9RenderSystem::_addManualDepthBuffer( IDirect3DDevice9* depthSurfaceDevice, IDirect3DSurface9 *depthSurface )
2937 	{
2938 		//If this depth buffer was already added, return that one
2939 		DepthBufferVec::const_iterator itor = mDepthBufferPool[DepthBuffer::POOL_DEFAULT].begin();
2940 		DepthBufferVec::const_iterator end  = mDepthBufferPool[DepthBuffer::POOL_DEFAULT].end();
2941 
2942 		while( itor != end )
2943 		{
2944 			if( static_cast<D3D9DepthBuffer*>(*itor)->getDepthBufferSurface() == depthSurface )
2945 				return *itor;
2946 
2947 			++itor;
2948 		}
2949 
2950 		//Nope, get the info about this depth buffer and create a new container fot it
2951 		D3DSURFACE_DESC dsDesc;
2952 		if( FAILED(depthSurface->GetDesc(&dsDesc)) )
2953 			return 0;
2954 
2955 		D3D9DepthBuffer *newDepthBuffer = OGRE_NEW D3D9DepthBuffer( DepthBuffer::POOL_DEFAULT, this,
2956 												depthSurfaceDevice, depthSurface,
2957 												dsDesc.Format, dsDesc.Width, dsDesc.Height,
2958 												dsDesc.MultiSampleType, dsDesc.MultiSampleQuality, true );
2959 
2960 		//Add the 'main' depth buffer to the pool
2961 		mDepthBufferPool[newDepthBuffer->getPoolId()].push_back( newDepthBuffer );
2962 
2963 		return newDepthBuffer;
2964 	}
2965 	//---------------------------------------------------------------------
_cleanupDepthBuffers(IDirect3DDevice9 * creator)2966 	void D3D9RenderSystem::_cleanupDepthBuffers( IDirect3DDevice9 *creator )
2967 	{
2968 		assert( creator );
2969 
2970 		DepthBufferMap::iterator itMap = mDepthBufferPool.begin();
2971 		DepthBufferMap::iterator enMap = mDepthBufferPool.end();
2972 
2973 		while( itMap != enMap )
2974 		{
2975 			DepthBufferVec::iterator itor = itMap->second.begin();
2976 			DepthBufferVec::iterator end  = itMap->second.end();
2977 
2978 			while( itor != end )
2979 			{
2980 				//Only delete those who match the specified creator
2981 				if( static_cast<D3D9DepthBuffer*>(*itor)->getDeviceCreator() == creator )
2982 				{
2983 					OGRE_DELETE *itor;
2984 
2985 					//Erasing a vector invalidates iterators, we need to recalculate
2986 					//to avoid memory corruption and asserts. The new itor will point
2987 					//to the next iterator
2988 					const size_t idx = itor - itMap->second.begin();
2989 					itMap->second.erase( itor );	//Erase
2990 					itor = itMap->second.begin() + idx;
2991 					end  = itMap->second.end();
2992 				}
2993 				else
2994 					++itor;
2995 			}
2996 
2997 			//Erase the pool if it's now empty. Note erasing from a map is
2998 			//valid while iterating through it
2999 			if( itMap->second.empty() )
3000 			{
3001 				DepthBufferMap::iterator deadi = itMap++;
3002 				mDepthBufferPool.erase( deadi );
3003 			}
3004 			else
3005 				++itMap;
3006 		}
3007 	}
3008 	//---------------------------------------------------------------------
_cleanupDepthBuffers(IDirect3DSurface9 * manualSurface)3009 	void D3D9RenderSystem::_cleanupDepthBuffers( IDirect3DSurface9 *manualSurface )
3010 	{
3011 		assert( manualSurface );
3012 
3013 		DepthBufferMap::iterator itMap = mDepthBufferPool.begin();
3014 		DepthBufferMap::iterator enMap = mDepthBufferPool.end();
3015 
3016 		while( itMap != enMap )
3017 		{
3018 			DepthBufferVec::iterator itor = itMap->second.begin();
3019 			DepthBufferVec::iterator end  = itMap->second.end();
3020 
3021 			while( itor != end )
3022 			{
3023 				//Only delete those who match the specified surface
3024 				if( static_cast<D3D9DepthBuffer*>(*itor)->getDepthBufferSurface() == manualSurface )
3025 				{
3026 					OGRE_DELETE *itor;
3027 
3028 					//Erasing a vector invalidates iterators, we need to recalculate
3029 					//to avoid memory corruption and asserts. The new itor will point
3030 					//to the next iterator
3031 					const size_t idx = itor - itMap->second.begin();
3032 					itMap->second.erase( itor );	//Erase
3033 					itor = itMap->second.begin() + idx;
3034 					end  = itMap->second.end();
3035 				}
3036 				else
3037 					++itor;
3038 			}
3039 
3040 			//Erase the pool if it's now empty. Note erasing from a map is
3041 			//valid while iterating through it
3042 			if( itMap->second.empty() )
3043 			{
3044 				DepthBufferMap::iterator deadi = itMap++;
3045 				mDepthBufferPool.erase( deadi );
3046 			}
3047 			else
3048 				++itMap;
3049 		}
3050 	}
3051 	//---------------------------------------------------------------------
_setRenderTarget(RenderTarget * target)3052 	void D3D9RenderSystem::_setRenderTarget(RenderTarget *target)
3053 	{
3054 		mActiveRenderTarget = target;
3055 
3056 		if (mActiveRenderTarget)
3057 		{
3058 			HRESULT hr;
3059 
3060 			// If this is called without going through RenderWindow::update, then
3061 			// the device will not have been set. Calling it twice is safe, the
3062 			// implementation ensures nothing happens if the same device is set twice
3063 			if (std::find(mRenderWindows.begin(), mRenderWindows.end(), target) != mRenderWindows.end())
3064 			{
3065 				D3D9RenderWindow *window = static_cast<D3D9RenderWindow*>(target);
3066 				mDeviceManager->setActiveRenderTargetDevice(window->getDevice());
3067 				// also make sure we validate the device; if this never went
3068 				// through update() it won't be set
3069 				window->_validateDevice();
3070 			}
3071 
3072 			// Retrieve render surfaces (up to OGRE_MAX_MULTIPLE_RENDER_TARGETS)
3073 			IDirect3DSurface9* pBack[OGRE_MAX_MULTIPLE_RENDER_TARGETS];
3074 			memset(pBack, 0, sizeof(pBack));
3075 			target->getCustomAttribute( "DDBACKBUFFER", &pBack );
3076 			if (!pBack[0])
3077 				return;
3078 
3079 			D3D9DepthBuffer *depthBuffer = static_cast<D3D9DepthBuffer*>(target->getDepthBuffer());
3080 
3081 			if( target->getDepthBufferPool() != DepthBuffer::POOL_NO_DEPTH &&
3082 				(!depthBuffer || depthBuffer->getDeviceCreator() != getActiveD3D9Device() ) )
3083 			{
3084 				//Depth is automatically managed and there is no depth buffer attached to this RT
3085 				//or the Current D3D device doesn't match the one this Depth buffer was created
3086 				setDepthBufferFor( target );
3087 
3088 				//Retrieve depth buffer again
3089 				depthBuffer = static_cast<D3D9DepthBuffer*>(target->getDepthBuffer());
3090 			}
3091 
3092 			if ((depthBuffer != NULL) && ( depthBuffer->getDeviceCreator() != getActiveD3D9Device()))
3093 			{
3094 				OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
3095 					"Can't use a depth buffer from a different device!",
3096 					"D3D9RenderSystem::_setRenderTarget" );
3097 			}
3098 
3099 			IDirect3DSurface9 *depthSurface = depthBuffer ? depthBuffer->getDepthBufferSurface() : NULL;
3100 
3101 			// Bind render targets
3102 			uint count = mCurrentCapabilities->getNumMultiRenderTargets();
3103 			for(uint x=0; x<count; ++x)
3104 			{
3105 				hr = getActiveD3D9Device()->SetRenderTarget(x, pBack[x]);
3106 				if (FAILED(hr))
3107 				{
3108 					String msg = DXGetErrorDescription(hr);
3109 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setRenderTarget : " + msg, "D3D9RenderSystem::_setViewport" );
3110 				}
3111 			}
3112 			hr = getActiveD3D9Device()->SetDepthStencilSurface( depthSurface );
3113 			if (FAILED(hr))
3114 			{
3115 				String msg = DXGetErrorDescription(hr);
3116 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to setDepthStencil : " + msg, "D3D9RenderSystem::_setViewport" );
3117 			}
3118 		}
3119 	}
3120 	//---------------------------------------------------------------------
_setViewport(Viewport * vp)3121 	void D3D9RenderSystem::_setViewport( Viewport *vp )
3122 	{
3123 		if (!vp)
3124 		{
3125 			mActiveViewport = NULL;
3126 			_setRenderTarget(NULL);
3127 		}
3128 		else if( vp != mActiveViewport || vp->_isUpdated() )
3129 		{
3130 			mActiveViewport = vp;
3131 
3132 			// ok, it's different, time to set render target and viewport params
3133 			D3DVIEWPORT9 d3dvp;
3134 			HRESULT hr;
3135 
3136 			// Set render target
3137 			RenderTarget* target = vp->getTarget();
3138 			_setRenderTarget(target);
3139 
3140 			//Reset the viewport after the render target has been set. If the device
3141 			//had been reset the viewport would have been set to NULL.
3142 			mActiveViewport = vp;
3143 
3144 			_setCullingMode( mCullingMode );
3145 
3146 			// set viewport dimensions
3147 			d3dvp.X = vp->getActualLeft();
3148 			d3dvp.Y = vp->getActualTop();
3149 			d3dvp.Width = vp->getActualWidth();
3150 			d3dvp.Height = vp->getActualHeight();
3151 			if (target->requiresTextureFlipping())
3152 			{
3153 				// Convert "top-left" to "bottom-left"
3154 				d3dvp.Y = target->getHeight() - d3dvp.Height - d3dvp.Y;
3155 			}
3156 
3157 			// Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
3158 			d3dvp.MinZ = 0.0f;
3159 			d3dvp.MaxZ = 1.0f;
3160 
3161 			if( FAILED( hr = getActiveD3D9Device()->SetViewport( &d3dvp ) ) )
3162 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set viewport.", "D3D9RenderSystem::_setViewport" );
3163 
3164 			// Set sRGB write mode
3165 			__SetRenderState(D3DRS_SRGBWRITEENABLE, target->isHardwareGammaEnabled());
3166 
3167 			vp->_clearUpdatedFlag();
3168 		}
3169 	}
3170 	//---------------------------------------------------------------------
_beginFrame()3171 	void D3D9RenderSystem::_beginFrame()
3172 	{
3173 		HRESULT hr;
3174 
3175 		if( !mActiveViewport )
3176 			OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR, "Cannot begin frame - no viewport selected.", "D3D9RenderSystem::_beginFrame" );
3177 
3178 		if( FAILED( hr = getActiveD3D9Device()->BeginScene() ) )
3179 		{
3180 			String msg = DXGetErrorDescription(hr);
3181 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error beginning frame :" + msg, "D3D9RenderSystem::_beginFrame" );
3182 		}
3183 
3184 		mLastVertexSourceCount = 0;
3185 
3186 		// Clear left overs of previous viewport.
3187 		// I.E: Viewport A can use 3 different textures and light states
3188 		// When trying to render viewport B these settings should be cleared, otherwise
3189 		// graphical artifacts might occur.
3190  		mDeviceManager->getActiveDevice()->clearDeviceStreams();
3191 	}
3192 	//---------------------------------------------------------------------
_endFrame()3193 	void D3D9RenderSystem::_endFrame()
3194 	{
3195 		HRESULT hr;
3196 		if( FAILED( hr = getActiveD3D9Device()->EndScene() ) )
3197 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error ending frame", "D3D9RenderSystem::_endFrame" );
3198 
3199 		mDeviceManager->destroyInactiveRenderDevices();
3200 	}
3201 	//---------------------------------------------------------------------
3202 	struct D3D9RenderContext : public RenderSystem::RenderSystemContext
3203 	{
3204 		RenderTarget* target;
3205 	};
3206 	//---------------------------------------------------------------------
_pauseFrame(void)3207 	RenderSystem::RenderSystemContext* D3D9RenderSystem::_pauseFrame(void)
3208 	{
3209 		//Stop rendering
3210 		_endFrame();
3211 
3212 		D3D9RenderContext* context = OGRE_ALLOC_T(D3D9RenderContext, 1, MEMCATEGORY_RENDERSYS);
3213 		context->target = mActiveRenderTarget;
3214 
3215 
3216 		return context;
3217 	}
3218 	//---------------------------------------------------------------------
_resumeFrame(RenderSystemContext * context)3219 	void D3D9RenderSystem::_resumeFrame(RenderSystemContext* context)
3220 	{
3221 		//Resume rendering
3222 		_beginFrame();
3223 		D3D9RenderContext* d3dContext = static_cast<D3D9RenderContext*>(context);
3224 
3225 		OGRE_FREE(context, MEMCATEGORY_RENDERSYS);
3226 	}
setVertexDeclaration(VertexDeclaration * decl)3227 	void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl)
3228 	{
3229         setVertexDeclaration(decl, true);
3230     }
3231 	//---------------------------------------------------------------------
setVertexDeclaration(VertexDeclaration * decl,bool useGlobalInstancingVertexBufferIsAvailable)3232 	void D3D9RenderSystem::setVertexDeclaration(VertexDeclaration* decl, bool useGlobalInstancingVertexBufferIsAvailable)
3233 	{
3234 		HRESULT hr;
3235 
3236 		D3D9VertexDeclaration* d3ddecl =
3237 			static_cast<D3D9VertexDeclaration*>(decl);
3238 
3239 		if (FAILED(hr = getActiveD3D9Device()->SetVertexDeclaration(d3ddecl->getD3DVertexDeclaration(getGlobalInstanceVertexBufferVertexDeclaration(), useGlobalInstancingVertexBufferIsAvailable))))
3240 		{
3241 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 vertex declaration",
3242 				"D3D9RenderSystem::setVertexDeclaration");
3243 		}
3244 
3245 	}
3246 	//---------------------------------------------------------------------
setVertexBufferBinding(VertexBufferBinding * binding)3247 	void D3D9RenderSystem::setVertexBufferBinding(VertexBufferBinding* binding)
3248 	{
3249 		setVertexBufferBinding(binding, 1, true, false);
3250 	}
3251 	//---------------------------------------------------------------------
setVertexBufferBinding(VertexBufferBinding * binding,size_t numberOfInstances,bool useGlobalInstancingVertexBufferIsAvailable,bool indexesUsed)3252 	void D3D9RenderSystem::setVertexBufferBinding(
3253         VertexBufferBinding* binding, size_t numberOfInstances, bool useGlobalInstancingVertexBufferIsAvailable, bool indexesUsed)
3254 	{
3255 		/*if (!prg)
3256 		{
3257 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3258 				"Null program bound.",
3259 				"D3D9RenderSystem::bindGpuProgram");
3260 		}*/
3261 
3262 		HRESULT hr;
3263 
3264         if (useGlobalInstancingVertexBufferIsAvailable)
3265         {
3266             numberOfInstances *= getGlobalNumberOfInstances();
3267         }
3268 
3269         HardwareVertexBufferSharedPtr globalInstanceVertexBuffer = getGlobalInstanceVertexBuffer();
3270         VertexDeclaration* globalVertexDeclaration = getGlobalInstanceVertexBufferVertexDeclaration();
3271         bool hasInstanceData = useGlobalInstancingVertexBufferIsAvailable &&
3272                     !globalInstanceVertexBuffer.isNull() && globalVertexDeclaration != NULL
3273                 || binding->hasInstanceData();
3274 
3275 
3276 		// TODO: attempt to detect duplicates
3277 		const VertexBufferBinding::VertexBufferBindingMap& binds = binding->getBindings();
3278 		VertexBufferBinding::VertexBufferBindingMap::const_iterator i, iend;
3279 		size_t source = 0;
3280 		iend = binds.end();
3281 		for (i = binds.begin(); i != iend; ++i, ++source)
3282 		{
3283 			D3D9HardwareVertexBuffer* d3d9buf =
3284 				static_cast<D3D9HardwareVertexBuffer*>(i->second.get());
3285 
3286 			// Unbind gap sources
3287 			for ( ; source < i->first; ++source)
3288 			{
3289 				hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(source), NULL, 0, 0);
3290 				if (FAILED(hr))
3291 				{
3292 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source",
3293 						"D3D9RenderSystem::setVertexBufferBinding");
3294 				}
3295 			}
3296 
3297 			hr = getActiveD3D9Device()->SetStreamSource(
3298 				    static_cast<UINT>(source),
3299 				    d3d9buf->getD3D9VertexBuffer(),
3300 				    0, // no stream offset, this is handled in _render instead
3301 				    static_cast<UINT>(d3d9buf->getVertexSize()) // stride
3302 				    );
3303 
3304 			if (FAILED(hr))
3305 			{
3306 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source for buffer binding",
3307 					"D3D9RenderSystem::setVertexBufferBinding");
3308 			}
3309 
3310             // SetStreamSourceFreq
3311             if ( hasInstanceData )
3312             {
3313 		        if ( d3d9buf->isInstanceData() )
3314 		        {
3315 			        hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INSTANCEDATA | d3d9buf->getInstanceDataStepRate() );
3316 		        }
3317 		        else
3318 		        {
3319 		            if ( !indexesUsed )
3320                     {
3321 			            OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Instance data used without index data.",
3322 				            "D3D9RenderSystem::setVertexBufferBinding");
3323                     }
3324 			        hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INDEXEDDATA | numberOfInstances );
3325 		        }
3326 		        if (FAILED(hr))
3327 		        {
3328 			        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source Freq",
3329 				        "D3D9RenderSystem::setVertexBufferBinding");
3330 		        }
3331             }
3332             else
3333             {
3334 			    hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), 1 );
3335 			    if (FAILED(hr))
3336 			    {
3337 				    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source Freq",
3338 					    "D3D9RenderSystem::setVertexBufferBinding");
3339 			    }
3340             }
3341 
3342 		}
3343 
3344         if (useGlobalInstancingVertexBufferIsAvailable)
3345         {
3346         // bind global instance buffer if exist
3347         if( !globalInstanceVertexBuffer.isNull() )
3348         {
3349 		    if ( !indexesUsed )
3350             {
3351 			    OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Instance data used without index data.",
3352 				    "D3D9RenderSystem::setVertexBufferBinding");
3353             }
3354 
3355 			D3D9HardwareVertexBuffer * d3d9buf =
3356 				static_cast<D3D9HardwareVertexBuffer*>(globalInstanceVertexBuffer.get());
3357 
3358 			hr = getActiveD3D9Device()->SetStreamSource(
3359 				    static_cast<UINT>(source),
3360 				    d3d9buf->getD3D9VertexBuffer(),
3361 				    0, // no stream offset, this is handled in _render instead
3362 				    static_cast<UINT>(d3d9buf->getVertexSize()) // stride
3363 				    );
3364 
3365 			if (FAILED(hr))
3366 			{
3367 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source for buffer binding",
3368 					"D3D9RenderSystem::setVertexBufferBinding");
3369 			}
3370 
3371 		    hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(source), D3DSTREAMSOURCE_INSTANCEDATA | d3d9buf->getInstanceDataStepRate() );
3372 			if (FAILED(hr))
3373 			{
3374 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set D3D9 stream source Freq",
3375 					"D3D9RenderSystem::setVertexBufferBinding");
3376 			}
3377         }
3378 
3379         }
3380 
3381 		// Unbind any unused sources
3382 		for (size_t unused = source; unused < mLastVertexSourceCount; ++unused)
3383 		{
3384 
3385 			hr = getActiveD3D9Device()->SetStreamSource(static_cast<UINT>(unused), NULL, 0, 0);
3386 			if (FAILED(hr))
3387 			{
3388 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source",
3389 					"D3D9RenderSystem::setVertexBufferBinding");
3390 			}
3391 
3392 			hr = getActiveD3D9Device()->SetStreamSourceFreq( static_cast<UINT>(unused), 1 );
3393 			if (FAILED(hr))
3394 			{
3395 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to reset unused D3D9 stream source Freq",
3396 					"D3D9RenderSystem::setVertexBufferBinding");
3397 			}
3398 
3399 		}
3400 		mLastVertexSourceCount = source;
3401 
3402 	}
3403 	//---------------------------------------------------------------------
_render(const RenderOperation & op)3404 	void D3D9RenderSystem::_render(const RenderOperation& op)
3405 	{
3406 		// Exit immediately if there is nothing to render
3407 		// This caused a problem on FireGL 8800
3408 		if (op.vertexData->vertexCount == 0)
3409 			return;
3410 
3411 		// Call super class
3412 		RenderSystem::_render(op);
3413 
3414 
3415 		if ( !mEnableFixedPipeline && !mRealCapabilities->hasCapability(RSC_FIXED_FUNCTION)
3416 			 &&
3417 			 (
3418 				( !mVertexProgramBound ) ||
3419 				(!mFragmentProgramBound && op.operationType != RenderOperation::OT_POINT_LIST)
3420 			  )
3421 		   )
3422 		{
3423 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3424 				"Attempted to render using the fixed pipeline when it is disabled.",
3425 				"D3D9RenderSystem::_render");
3426 		}
3427 
3428 		// To think about: possibly remove setVertexDeclaration and
3429 		// setVertexBufferBinding from RenderSystem since the sequence is
3430 		// a bit too D3D9-specific?
3431 		setVertexDeclaration(op.vertexData->vertexDeclaration, op.useGlobalInstancingVertexBufferIsAvailable);
3432 		setVertexBufferBinding(op.vertexData->vertexBufferBinding, op.numberOfInstances, op.useGlobalInstancingVertexBufferIsAvailable, op.useIndexes);
3433 
3434 		// Determine rendering operation
3435 		D3DPRIMITIVETYPE primType = D3DPT_TRIANGLELIST;
3436 		DWORD primCount = 0;
3437 		switch( op.operationType )
3438 		{
3439 		case RenderOperation::OT_POINT_LIST:
3440 			primType = D3DPT_POINTLIST;
3441 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount);
3442 			break;
3443 
3444 		case RenderOperation::OT_LINE_LIST:
3445 			primType = D3DPT_LINELIST;
3446 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 2;
3447 			break;
3448 
3449 		case RenderOperation::OT_LINE_STRIP:
3450 			primType = D3DPT_LINESTRIP;
3451 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 1;
3452 			break;
3453 
3454 		case RenderOperation::OT_TRIANGLE_LIST:
3455 			primType = D3DPT_TRIANGLELIST;
3456 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) / 3;
3457 			break;
3458 
3459 		case RenderOperation::OT_TRIANGLE_STRIP:
3460 			primType = D3DPT_TRIANGLESTRIP;
3461 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
3462 			break;
3463 
3464 		case RenderOperation::OT_TRIANGLE_FAN:
3465 			primType = D3DPT_TRIANGLEFAN;
3466 			primCount = static_cast<DWORD>(op.useIndexes ? op.indexData->indexCount : op.vertexData->vertexCount) - 2;
3467 			break;
3468 		}
3469 
3470 		if (!primCount)
3471 			return;
3472 
3473 		// Issue the op
3474 		HRESULT hr;
3475 		if( op.useIndexes )
3476 		{
3477 			D3D9HardwareIndexBuffer* d3dIdxBuf =
3478 				static_cast<D3D9HardwareIndexBuffer*>(op.indexData->indexBuffer.get());
3479 			hr = getActiveD3D9Device()->SetIndices( d3dIdxBuf->getD3DIndexBuffer() );
3480 			if (FAILED(hr))
3481 			{
3482 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to set index buffer", "D3D9RenderSystem::_render" );
3483 			}
3484 
3485 			do
3486 			{
3487 				// Update derived depth bias
3488 				if (mDerivedDepthBias && mCurrentPassIterationNum > 0)
3489 				{
3490 					_setDepthBias(mDerivedDepthBiasBase +
3491 						mDerivedDepthBiasMultiplier * mCurrentPassIterationNum,
3492 						mDerivedDepthBiasSlopeScale);
3493 				}
3494 				// do indexed draw operation
3495 				hr = getActiveD3D9Device()->DrawIndexedPrimitive(
3496 					primType,
3497 					static_cast<INT>(op.vertexData->vertexStart),
3498 					0, // Min vertex index - assume we can go right down to 0
3499 					static_cast<UINT>(op.vertexData->vertexCount),
3500 					static_cast<UINT>(op.indexData->indexStart),
3501 					static_cast<UINT>(primCount)
3502 					);
3503 
3504 			} while (updatePassIterationRenderState());
3505 		}
3506 		else
3507 		{
3508 			// nfz: gpu_iterate
3509 			do
3510 			{
3511 				// Update derived depth bias
3512 				if (mDerivedDepthBias && mCurrentPassIterationNum > 0)
3513 				{
3514 					_setDepthBias(mDerivedDepthBiasBase +
3515 						mDerivedDepthBiasMultiplier * mCurrentPassIterationNum,
3516 						mDerivedDepthBiasSlopeScale);
3517 				}
3518 				// Unindexed, a little simpler!
3519 				hr = getActiveD3D9Device()->DrawPrimitive(
3520 					primType,
3521 					static_cast<UINT>(op.vertexData->vertexStart),
3522 					static_cast<UINT>(primCount)
3523 					);
3524 
3525 			} while (updatePassIterationRenderState());
3526 		}
3527 
3528 		if( FAILED( hr ) )
3529 		{
3530 			String msg = DXGetErrorDescription(hr);
3531 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Failed to DrawPrimitive : " + msg, "D3D9RenderSystem::_render" );
3532 		}
3533 
3534 	}
3535 	//---------------------------------------------------------------------
setNormaliseNormals(bool normalise)3536 	void D3D9RenderSystem::setNormaliseNormals(bool normalise)
3537 	{
3538 		__SetRenderState(D3DRS_NORMALIZENORMALS,
3539 			normalise ? TRUE : FALSE);
3540 	}
3541 	//---------------------------------------------------------------------
bindGpuProgram(GpuProgram * prg)3542 	void D3D9RenderSystem::bindGpuProgram(GpuProgram* prg)
3543 	{
3544 		if (!prg)
3545 		{
3546 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3547 				"Null program bound.",
3548 				"D3D9RenderSystem::bindGpuProgram");
3549 		}
3550 
3551 		HRESULT hr;
3552 		switch (prg->getType())
3553 		{
3554 		case GPT_VERTEX_PROGRAM:
3555 			hr = getActiveD3D9Device()->SetVertexShader(
3556 				static_cast<D3D9GpuVertexProgram*>(prg)->getVertexShader());
3557 			if (FAILED(hr))
3558 			{
3559 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetVertexShader", "D3D9RenderSystem::bindGpuProgram");
3560 			}
3561 			break;
3562 		case GPT_FRAGMENT_PROGRAM:
3563 			hr = getActiveD3D9Device()->SetPixelShader(
3564 				static_cast<D3D9GpuFragmentProgram*>(prg)->getPixelShader());
3565 			if (FAILED(hr))
3566 			{
3567 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error calling SetPixelShader", "D3D9RenderSystem::bindGpuProgram");
3568 			}
3569 			break;
3570 		};
3571 
3572 		// Make sure texcoord index is equal to stage value, As SDK Doc suggests:
3573 		// "When rendering using vertex shaders, each stage's texture coordinate index must be set to its default value."
3574 		// This solves such an errors when working with the Debug runtime -
3575 		// "Direct3D9: (ERROR) :Stage 1 - Texture coordinate index in the stage must be equal to the stage index when programmable vertex pipeline is used".
3576 		for (unsigned int nStage=0; nStage < 8; ++nStage)
3577 			__SetTextureStageState(nStage, D3DTSS_TEXCOORDINDEX, nStage);
3578 
3579 		RenderSystem::bindGpuProgram(prg);
3580 
3581 	}
3582 	//---------------------------------------------------------------------
unbindGpuProgram(GpuProgramType gptype)3583 	void D3D9RenderSystem::unbindGpuProgram(GpuProgramType gptype)
3584 	{
3585 		/*if (!prg)
3586 		{
3587 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3588 				"Null program bound.",
3589 				"D3D9RenderSystem::bindGpuProgram");
3590 		}*/
3591 
3592 		HRESULT hr;
3593 		switch(gptype)
3594 		{
3595 		case GPT_VERTEX_PROGRAM:
3596 			mActiveVertexGpuProgramParameters.setNull();
3597 			hr = getActiveD3D9Device()->SetVertexShader(NULL);
3598 			if (FAILED(hr))
3599 			{
3600 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetVertexShader to NULL",
3601 					"D3D9RenderSystem::unbindGpuProgram");
3602 			}
3603 			break;
3604 		case GPT_FRAGMENT_PROGRAM:
3605 			mActiveFragmentGpuProgramParameters.setNull();
3606 			hr = getActiveD3D9Device()->SetPixelShader(NULL);
3607 			if (FAILED(hr))
3608 			{
3609 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error resetting SetPixelShader to NULL",
3610 					"D3D9RenderSystem::unbindGpuProgram");
3611 			}
3612 			break;
3613 		};
3614 		RenderSystem::unbindGpuProgram(gptype);
3615 	}
3616 	//---------------------------------------------------------------------
bindGpuProgramParameters(GpuProgramType gptype,GpuProgramParametersSharedPtr params,uint16 variability)3617 	void D3D9RenderSystem::bindGpuProgramParameters(GpuProgramType gptype,
3618 		GpuProgramParametersSharedPtr params, uint16 variability)
3619 	{
3620 		// special case pass iteration
3621 		if (variability == (uint16)GPV_PASS_ITERATION_NUMBER)
3622 		{
3623 			bindGpuProgramPassIterationParameters(gptype);
3624 			return;
3625 		}
3626 
3627 		if (variability & (uint16)GPV_GLOBAL)
3628 		{
3629 			// D3D9 doesn't support shared constant buffers, so use copy routine
3630 			params->_copySharedParams();
3631 		}
3632 
3633 		HRESULT hr;
3634 		GpuLogicalBufferStructPtr floatLogical = params->getFloatLogicalBufferStruct();
3635 		GpuLogicalBufferStructPtr intLogical = params->getIntLogicalBufferStruct();
3636 
3637 		switch(gptype)
3638 		{
3639 		case GPT_VERTEX_PROGRAM:
3640 			mActiveVertexGpuProgramParameters = params;
3641 			{
3642                             OGRE_LOCK_MUTEX(floatLogical->mutex);
3643 
3644 					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
3645 						i != floatLogical->map.end(); ++i)
3646 					{
3647 						if (i->second.variability & variability)
3648 						{
3649 							size_t logicalIndex = i->first;
3650 							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
3651 							size_t slotCount = i->second.currentSize / 4;
3652 							assert (i->second.currentSize % 4 == 0 && "Should not have any "
3653 								"elements less than 4 wide for D3D9");
3654 
3655 						if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF(
3656 							(UINT)logicalIndex, pFloat, (UINT)slotCount)))
3657 							{
3658 								OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3659 									"Unable to upload vertex shader float parameters",
3660 									"D3D9RenderSystem::bindGpuProgramParameters");
3661 							}
3662 						}
3663 
3664 					}
3665 
3666 			}
3667 			// bind ints
3668 			{
3669                             OGRE_LOCK_MUTEX(intLogical->mutex);
3670 
3671 					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
3672 						i != intLogical->map.end(); ++i)
3673 					{
3674 						if (i->second.variability & variability)
3675 						{
3676 							size_t logicalIndex = i->first;
3677 							const int* pInt = params->getIntPointer(i->second.physicalIndex);
3678 							size_t slotCount = i->second.currentSize / 4;
3679 							assert (i->second.currentSize % 4 == 0 && "Should not have any "
3680 								"elements less than 4 wide for D3D9");
3681 
3682 						if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantI(
3683 							static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
3684 							{
3685 								OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3686 									"Unable to upload vertex shader int parameters",
3687 									"D3D9RenderSystem::bindGpuProgramParameters");
3688 							}
3689 						}
3690 					}
3691 
3692 			}
3693 
3694 			break;
3695 		case GPT_FRAGMENT_PROGRAM:
3696 			mActiveFragmentGpuProgramParameters = params;
3697 			{
3698                             OGRE_LOCK_MUTEX(floatLogical->mutex);
3699 
3700 					for (GpuLogicalIndexUseMap::const_iterator i = floatLogical->map.begin();
3701 						i != floatLogical->map.end(); ++i)
3702 					{
3703 						if (i->second.variability & variability)
3704 						{
3705 							size_t logicalIndex = i->first;
3706 							const float* pFloat = params->getFloatPointer(i->second.physicalIndex);
3707 							size_t slotCount = i->second.currentSize / 4;
3708 							assert (i->second.currentSize % 4 == 0 && "Should not have any "
3709 								"elements less than 4 wide for D3D9");
3710 
3711 						if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF(
3712 							static_cast<UINT>(logicalIndex), pFloat, static_cast<UINT>(slotCount))))
3713 							{
3714 								OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3715 									"Unable to upload pixel shader float parameters",
3716 									"D3D9RenderSystem::bindGpuProgramParameters");
3717 							}
3718 						}
3719 					}
3720 
3721 			}
3722 			// bind ints
3723 			{
3724                             OGRE_LOCK_MUTEX(intLogical->mutex);
3725 
3726 					for (GpuLogicalIndexUseMap::const_iterator i = intLogical->map.begin();
3727 						i != intLogical->map.end(); ++i)
3728 					{
3729 						if (i->second.variability & variability)
3730 						{
3731 							size_t logicalIndex = i->first;
3732 							const int* pInt = params->getIntPointer(i->second.physicalIndex);
3733 							size_t slotCount = i->second.currentSize / 4;
3734 							assert (i->second.currentSize % 4 == 0 && "Should not have any "
3735 								"elements less than 4 wide for D3D9");
3736 
3737 						if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantI(
3738 							static_cast<UINT>(logicalIndex), pInt, static_cast<UINT>(slotCount))))
3739 							{
3740 								OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3741 									"Unable to upload pixel shader int parameters",
3742 									"D3D9RenderSystem::bindGpuProgramParameters");
3743 							}
3744 						}
3745 
3746 					}
3747 
3748 			}
3749 			break;
3750 		};
3751 	}
3752 	//---------------------------------------------------------------------
bindGpuProgramPassIterationParameters(GpuProgramType gptype)3753 	void D3D9RenderSystem::bindGpuProgramPassIterationParameters(GpuProgramType gptype)
3754 	{
3755 
3756 		HRESULT hr;
3757 		size_t physicalIndex = 0;
3758 		size_t logicalIndex = 0;
3759 		const float* pFloat;
3760 
3761 		switch(gptype)
3762 		{
3763 		case GPT_VERTEX_PROGRAM:
3764 			if (mActiveVertexGpuProgramParameters->hasPassIterationNumber())
3765 			{
3766 				physicalIndex = mActiveVertexGpuProgramParameters->getPassIterationNumberIndex();
3767 				logicalIndex = mActiveVertexGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex);
3768 				pFloat = mActiveVertexGpuProgramParameters->getFloatPointer(physicalIndex);
3769 
3770 				if (FAILED(hr = getActiveD3D9Device()->SetVertexShaderConstantF(
3771 					static_cast<UINT>(logicalIndex), pFloat, 1)))
3772 				{
3773 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3774 						"Unable to upload vertex shader multi pass parameters",
3775 						"D3D9RenderSystem::bindGpuProgramMultiPassParameters");
3776 				}
3777 			}
3778 			break;
3779 
3780 		case GPT_FRAGMENT_PROGRAM:
3781 			if (mActiveFragmentGpuProgramParameters->hasPassIterationNumber())
3782 			{
3783 				physicalIndex = mActiveFragmentGpuProgramParameters->getPassIterationNumberIndex();
3784 				logicalIndex = mActiveFragmentGpuProgramParameters->getFloatLogicalIndexForPhysicalIndex(physicalIndex);
3785 				pFloat = mActiveFragmentGpuProgramParameters->getFloatPointer(physicalIndex);
3786 				if (FAILED(hr = getActiveD3D9Device()->SetPixelShaderConstantF(
3787 					static_cast<UINT>(logicalIndex), pFloat, 1)))
3788 				{
3789 					OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR,
3790 						"Unable to upload pixel shader multi pass parameters",
3791 						"D3D9RenderSystem::bindGpuProgramMultiPassParameters");
3792 				}
3793 			}
3794 			break;
3795 
3796 		}
3797 	}
3798 	//---------------------------------------------------------------------
setClipPlanesImpl(const PlaneList & clipPlanes)3799 	void D3D9RenderSystem::setClipPlanesImpl(const PlaneList& clipPlanes)
3800 	{
3801 		size_t i;
3802 		size_t numClipPlanes;
3803 		D3DXPLANE dx9ClipPlane;
3804 		DWORD mask = 0;
3805 		HRESULT hr;
3806 
3807 		numClipPlanes = clipPlanes.size();
3808 		for (i = 0; i < numClipPlanes; ++i)
3809 		{
3810 			const Plane& plane = clipPlanes[i];
3811 
3812 			dx9ClipPlane.a = plane.normal.x;
3813 			dx9ClipPlane.b = plane.normal.y;
3814 			dx9ClipPlane.c = plane.normal.z;
3815 			dx9ClipPlane.d = plane.d;
3816 
3817 			if (mVertexProgramBound)
3818 			{
3819 				// programmable clips in clip space (ugh)
3820 				// must transform worldspace planes by view/proj
3821 				D3DXMATRIX xform;
3822 				D3DXMatrixMultiply(&xform, &mDxViewMat, &mDxProjMat);
3823 				D3DXMatrixInverse(&xform, NULL, &xform);
3824 				D3DXMatrixTranspose(&xform, &xform);
3825 				D3DXPlaneTransform(&dx9ClipPlane, &dx9ClipPlane, &xform);
3826 			}
3827 
3828 			hr = getActiveD3D9Device()->SetClipPlane(static_cast<DWORD>(i), dx9ClipPlane);
3829 			if (FAILED(hr))
3830 			{
3831 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set clip plane",
3832 					"D3D9RenderSystem::setClipPlanes");
3833 			}
3834 
3835 			mask |= (1 << i);
3836 		}
3837 
3838 		hr = __SetRenderState(D3DRS_CLIPPLANEENABLE, mask);
3839 		if (FAILED(hr))
3840 		{
3841 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set render state for clip planes",
3842 				"D3D9RenderSystem::setClipPlanes");
3843 		}
3844 	}
3845 	//---------------------------------------------------------------------
setScissorTest(bool enabled,size_t left,size_t top,size_t right,size_t bottom)3846 	void D3D9RenderSystem::setScissorTest(bool enabled, size_t left, size_t top, size_t right,
3847 		size_t bottom)
3848 	{
3849 		HRESULT hr;
3850 		if (enabled)
3851 		{
3852 			if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE)))
3853 			{
3854 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to enable scissor rendering state; " + getErrorDescription(hr),
3855 					"D3D9RenderSystem::setScissorTest");
3856 			}
3857 			RECT rect;
3858 			rect.left = static_cast<LONG>(left);
3859 			rect.top = static_cast<LONG>(top);
3860 			rect.bottom = static_cast<LONG>(bottom);
3861 			rect.right = static_cast<LONG>(right);
3862 			if (FAILED(hr = getActiveD3D9Device()->SetScissorRect(&rect)))
3863 			{
3864 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to set scissor rectangle; " + getErrorDescription(hr),
3865 					"D3D9RenderSystem::setScissorTest");
3866 			}
3867 		}
3868 		else
3869 		{
3870 			if (FAILED(hr = __SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE)))
3871 			{
3872 				OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Unable to disable scissor rendering state; " + getErrorDescription(hr),
3873 					"D3D9RenderSystem::setScissorTest");
3874 			}
3875 		}
3876 	}
3877 	//---------------------------------------------------------------------
clearFrameBuffer(unsigned int buffers,const ColourValue & colour,Real depth,unsigned short stencil)3878 	void D3D9RenderSystem::clearFrameBuffer(unsigned int buffers,
3879 		const ColourValue& colour, Real depth, unsigned short stencil)
3880 	{
3881 		DWORD flags = 0;
3882 		if (buffers & FBT_COLOUR)
3883 		{
3884 			flags |= D3DCLEAR_TARGET;
3885 		}
3886 		if (buffers & FBT_DEPTH)
3887 		{
3888 			flags |= D3DCLEAR_ZBUFFER;
3889 		}
3890 		// Only try to clear the stencil buffer if supported
3891 		if (buffers & FBT_STENCIL && mCurrentCapabilities->hasCapability(RSC_HWSTENCIL))
3892 		{
3893 			flags |= D3DCLEAR_STENCIL;
3894 		}
3895 		HRESULT hr;
3896 		if( FAILED( hr = getActiveD3D9Device()->Clear(
3897 			0,
3898 			NULL,
3899 			flags,
3900 			colour.getAsARGB(),
3901 			depth,
3902 			stencil ) ) )
3903 		{
3904 			String msg = DXGetErrorDescription(hr);
3905 			OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Error clearing frame buffer : "
3906 				+ msg, "D3D9RenderSystem::clearFrameBuffer" );
3907 		}
3908 	}
3909 	//---------------------------------------------------------------------
_makeProjectionMatrix(Real left,Real right,Real bottom,Real top,Real nearPlane,Real farPlane,Matrix4 & dest,bool forGpuProgram)3910 	void D3D9RenderSystem::_makeProjectionMatrix(Real left, Real right,
3911 		Real bottom, Real top, Real nearPlane, Real farPlane, Matrix4& dest,
3912 		bool forGpuProgram)
3913 	{
3914 		// Correct position for off-axis projection matrix
3915 		if (!forGpuProgram)
3916 		{
3917 			Real offsetX = left + right;
3918 			Real offsetY = top + bottom;
3919 
3920 			left -= offsetX;
3921 			right -= offsetX;
3922 			top -= offsetY;
3923 			bottom -= offsetY;
3924 		}
3925 
3926 		Real width = right - left;
3927 		Real height = top - bottom;
3928 		Real q, qn;
3929 		if (farPlane == 0)
3930 		{
3931 			q = 1 - Frustum::INFINITE_FAR_PLANE_ADJUST;
3932 			qn = nearPlane * (Frustum::INFINITE_FAR_PLANE_ADJUST - 1);
3933 		}
3934 		else
3935 		{
3936 			q = farPlane / ( farPlane - nearPlane );
3937 			qn = -q * nearPlane;
3938 		}
3939 		dest = Matrix4::ZERO;
3940 		dest[0][0] = 2 * nearPlane / width;
3941 		dest[0][2] = (right+left) / width;
3942 		dest[1][1] = 2 * nearPlane / height;
3943 		dest[1][2] = (top+bottom) / height;
3944 		if (forGpuProgram)
3945 		{
3946 			dest[2][2] = -q;
3947 			dest[3][2] = -1.0f;
3948 		}
3949 		else
3950 		{
3951 			dest[2][2] = q;
3952 			dest[3][2] = 1.0f;
3953 		}
3954 		dest[2][3] = qn;
3955 	}
3956 
3957 	// ------------------------------------------------------------------
setClipPlane(ushort index,Real A,Real B,Real C,Real D)3958 	void D3D9RenderSystem::setClipPlane (ushort index, Real A, Real B, Real C, Real D)
3959 	{
3960 		float plane[4] = { A, B, C, D };
3961 		getActiveD3D9Device()->SetClipPlane (index, plane);
3962 	}
3963 
3964 	// ------------------------------------------------------------------
enableClipPlane(ushort index,bool enable)3965 	void D3D9RenderSystem::enableClipPlane (ushort index, bool enable)
3966 	{
3967 		DWORD prev;
3968 		getActiveD3D9Device()->GetRenderState(D3DRS_CLIPPLANEENABLE, &prev);
3969 		__SetRenderState(D3DRS_CLIPPLANEENABLE, enable?
3970 			(prev | (1 << index)) : (prev & ~(1 << index)));
3971 	}
3972 	//---------------------------------------------------------------------
createHardwareOcclusionQuery()3973 	HardwareOcclusionQuery* D3D9RenderSystem::createHardwareOcclusionQuery()
3974 	{
3975 		D3D9HardwareOcclusionQuery* ret = OGRE_NEW D3D9HardwareOcclusionQuery();
3976 		mHwOcclusionQueries.push_back(ret);
3977 		return ret;
3978 	}
3979 	//---------------------------------------------------------------------
getHorizontalTexelOffset()3980 	Real D3D9RenderSystem::getHorizontalTexelOffset()
3981 	{
3982 		// D3D considers the origin to be in the center of a pixel
3983 		return -0.5f;
3984 	}
3985 	//---------------------------------------------------------------------
getVerticalTexelOffset()3986 	Real D3D9RenderSystem::getVerticalTexelOffset()
3987 	{
3988 		// D3D considers the origin to be in the center of a pixel
3989 		return -0.5f;
3990 	}
3991 	//---------------------------------------------------------------------
_applyObliqueDepthProjection(Matrix4 & matrix,const Plane & plane,bool forGpuProgram)3992 	void D3D9RenderSystem::_applyObliqueDepthProjection(Matrix4& matrix, const Plane& plane,
3993 		bool forGpuProgram)
3994 	{
3995 		// Thanks to Eric Lenyel for posting this calculation at www.terathon.com
3996 
3997 		// Calculate the clip-space corner point opposite the clipping plane
3998 		// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
3999 		// transform it into camera space by multiplying it
4000 		// by the inverse of the projection matrix
4001 
4002 		/* generalised version
4003 		Vector4 q = matrix.inverse() *
4004 		Vector4(Math::Sign(plane.normal.x), Math::Sign(plane.normal.y), 1.0f, 1.0f);
4005 		*/
4006 		Vector4 q;
4007 		q.x = Math::Sign(plane.normal.x) / matrix[0][0];
4008 		q.y = Math::Sign(plane.normal.y) / matrix[1][1];
4009 		q.z = 1.0F;
4010 		// flip the next bit from Lengyel since we're right-handed
4011 		if (forGpuProgram)
4012 		{
4013 			q.w = (1.0F - matrix[2][2]) / matrix[2][3];
4014 		}
4015 		else
4016 		{
4017 			q.w = (1.0F + matrix[2][2]) / matrix[2][3];
4018 		}
4019 
4020 		// Calculate the scaled plane vector
4021 		Vector4 clipPlane4d(plane.normal.x, plane.normal.y, plane.normal.z, plane.d);
4022 		Vector4 c = clipPlane4d * (1.0F / (clipPlane4d.dotProduct(q)));
4023 
4024 		// Replace the third row of the projection matrix
4025 		matrix[2][0] = c.x;
4026 		matrix[2][1] = c.y;
4027 		// flip the next bit from Lengyel since we're right-handed
4028 		if (forGpuProgram)
4029 		{
4030 			matrix[2][2] = c.z;
4031 		}
4032 		else
4033 		{
4034 			matrix[2][2] = -c.z;
4035 		}
4036 		matrix[2][3] = c.w;
4037 	}
4038 	//---------------------------------------------------------------------
getMinimumDepthInputValue()4039 	Real D3D9RenderSystem::getMinimumDepthInputValue()
4040 	{
4041 		// Range [0.0f, 1.0f]
4042 		return 0.0f;
4043 	}
4044 	//---------------------------------------------------------------------
getMaximumDepthInputValue()4045 	Real D3D9RenderSystem::getMaximumDepthInputValue()
4046 	{
4047 		// Range [0.0f, 1.0f]
4048 		// D3D inverts even identity view matrices, so maximum INPUT is -1.0
4049 		return -1.0f;
4050 	}
4051 	//---------------------------------------------------------------------
getDirect3D9()4052 	IDirect3D9*	D3D9RenderSystem::getDirect3D9()
4053 	{
4054 		IDirect3D9* pDirect3D9 = msD3D9RenderSystem->mD3D;
4055 
4056 		if (pDirect3D9 == NULL)
4057 		{
4058 			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
4059 				"Direct3D9 interface is NULL !!!",
4060 				"D3D9RenderSystem::getDirect3D9" );
4061 		}
4062 
4063 		return pDirect3D9;
4064 	}
4065 
4066 	//---------------------------------------------------------------------
getResourceCreationDeviceCount()4067 	UINT D3D9RenderSystem::getResourceCreationDeviceCount()
4068 	{
4069 		D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy();
4070 
4071 		if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE)
4072 		{
4073 			return 1;
4074 		}
4075 		else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES)
4076 		{
4077 			return msD3D9RenderSystem->mDeviceManager->getDeviceCount();
4078 		}
4079 
4080 		OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
4081 			"Invalid resource creation policy !!!",
4082 			"D3D9RenderSystem::getResourceCreationDeviceCount" );
4083 
4084 		return 0;
4085 	}
4086 
4087 	//---------------------------------------------------------------------
getResourceCreationDevice(UINT index)4088 	IDirect3DDevice9* D3D9RenderSystem::getResourceCreationDevice(UINT index)
4089 	{
4090 		D3D9ResourceCreationPolicy creationPolicy = msD3D9RenderSystem->mResourceManager->getCreationPolicy();
4091 		IDirect3DDevice9* d3d9Device = NULL;
4092 
4093 		if (creationPolicy == RCP_CREATE_ON_ACTIVE_DEVICE)
4094 		{
4095 			d3d9Device = msD3D9RenderSystem->getActiveD3D9Device();
4096 		}
4097 		else if (creationPolicy == RCP_CREATE_ON_ALL_DEVICES)
4098 		{
4099 			d3d9Device = msD3D9RenderSystem->mDeviceManager->getDevice(index)->getD3D9Device();
4100 		}
4101 		else
4102 		{
4103 			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
4104 				"Invalid resource creation policy !!!",
4105 				"D3D9RenderSystem::getResourceCreationDevice" );
4106 		}
4107 
4108 		return d3d9Device;
4109 	}
4110 
4111 	//---------------------------------------------------------------------
getActiveD3D9Device()4112 	IDirect3DDevice9* D3D9RenderSystem::getActiveD3D9Device()
4113 	{
4114 		D3D9Device* activeDevice = msD3D9RenderSystem->mDeviceManager->getActiveDevice();
4115 		IDirect3DDevice9* d3d9Device;
4116 
4117 		d3d9Device = activeDevice->getD3D9Device();
4118 
4119 		if (d3d9Device == NULL)
4120 		{
4121 			OGRE_EXCEPT( Exception::ERR_INVALIDPARAMS,
4122 				"Current d3d9 device is NULL !!!",
4123 				"D3D9RenderSystem::getActiveD3D9Device" );
4124 		}
4125 
4126 		return d3d9Device;
4127 	}
4128 
4129 	//---------------------------------------------------------------------
4130 	// Formats to try, in decreasing order of preference
4131 	D3DFORMAT ddDepthStencilFormats[]={
4132 		D3DFMT_D24FS8,
4133 		D3DFMT_D24S8,
4134 		D3DFMT_D24X4S4,
4135 		D3DFMT_D24X8,
4136 		D3DFMT_D15S1,
4137 		D3DFMT_D16,
4138 		D3DFMT_D32
4139 	};
4140 #define NDSFORMATS (sizeof(ddDepthStencilFormats)/sizeof(D3DFORMAT))
4141 
_getDepthStencilFormatFor(D3DFORMAT fmt)4142 	D3DFORMAT D3D9RenderSystem::_getDepthStencilFormatFor(D3DFORMAT fmt)
4143 	{
4144 		/// Check if result is cached
4145 		DepthStencilHash::iterator i = mDepthStencilHash.find((unsigned int)fmt);
4146 		if(i != mDepthStencilHash.end())
4147 			return i->second;
4148 		/// If not, probe with CheckDepthStencilMatch
4149 		D3DFORMAT dsfmt = D3DFMT_UNKNOWN;
4150 
4151 		/// Get description of primary render target
4152 		D3D9Device* activeDevice = mDeviceManager->getActiveDevice();
4153 		IDirect3DSurface9* mSurface = activeDevice->getPrimaryWindow()->getRenderSurface();
4154 		D3DSURFACE_DESC srfDesc;
4155 
4156 		if(mSurface && SUCCEEDED(mSurface->GetDesc(&srfDesc)))
4157 		{
4158 			/// Probe all depth stencil formats
4159 			/// Break on first one that matches
4160 			for(size_t x=0; x<NDSFORMATS; ++x)
4161 			{
4162 				// Verify that the depth format exists
4163 				if (mD3D->CheckDeviceFormat(
4164 					activeDevice->getAdapterNumber(),
4165 					activeDevice->getDeviceType(),
4166 					srfDesc.Format,
4167 					D3DUSAGE_DEPTHSTENCIL,
4168 					D3DRTYPE_SURFACE,
4169 					ddDepthStencilFormats[x]) != D3D_OK)
4170 				{
4171 					continue;
4172 				}
4173 				// Verify that the depth format is compatible
4174 				if(mD3D->CheckDepthStencilMatch(
4175 					activeDevice->getAdapterNumber(),
4176 					activeDevice->getDeviceType(),
4177 					srfDesc.Format,
4178 					fmt, ddDepthStencilFormats[x]) == D3D_OK)
4179 				{
4180 					dsfmt = ddDepthStencilFormats[x];
4181 					break;
4182 				}
4183 			}
4184 		}
4185 		/// Cache result
4186 		mDepthStencilHash[(unsigned int)fmt] = dsfmt;
4187 		return dsfmt;
4188 	}
4189 	//---------------------------------------------------------------------
registerThread()4190 	void D3D9RenderSystem::registerThread()
4191 	{
4192 		// nothing to do - D3D9 shares rendering context already
4193 	}
4194 	//---------------------------------------------------------------------
unregisterThread()4195 	void D3D9RenderSystem::unregisterThread()
4196 	{
4197 		// nothing to do - D3D9 shares rendering context already
4198 	}
4199 	//---------------------------------------------------------------------
preExtraThreadsStarted()4200 	void D3D9RenderSystem::preExtraThreadsStarted()
4201 	{
4202 		// nothing to do - D3D9 shares rendering context already
4203 	}
4204 	//---------------------------------------------------------------------
postExtraThreadsStarted()4205 	void D3D9RenderSystem::postExtraThreadsStarted()
4206 	{
4207 		// nothing to do - D3D9 shares rendering context already
4208 	}
4209 	//---------------------------------------------------------------------
getResourceManager()4210 	D3D9ResourceManager* D3D9RenderSystem::getResourceManager()
4211 	{
4212 		return msD3D9RenderSystem->mResourceManager;
4213 	}
4214 
4215 	//---------------------------------------------------------------------
getDeviceManager()4216 	D3D9DeviceManager* D3D9RenderSystem::getDeviceManager()
4217 	{
4218 		return msD3D9RenderSystem->mDeviceManager;
4219 	}
4220 
4221 	//---------------------------------------------------------------------
createRenderSystemCapabilities() const4222 	RenderSystemCapabilities* D3D9RenderSystem::createRenderSystemCapabilities() const
4223 	{
4224 		return mRealCapabilities;
4225 	}
4226 
4227 	//---------------------------------------------------------------------
getDisplayMonitorCount() const4228 	unsigned int D3D9RenderSystem::getDisplayMonitorCount() const
4229 	{
4230 		return mD3D->GetAdapterCount();
4231 	}
4232 
4233     //---------------------------------------------------------------------
beginProfileEvent(const String & eventName)4234     void D3D9RenderSystem::beginProfileEvent( const String &eventName )
4235     {
4236         if( eventName.empty() )
4237             return;
4238 
4239         vector<wchar_t>::type result(eventName.length() + 1, '\0');
4240         (void)MultiByteToWideChar(CP_ACP, 0, eventName.data(), eventName.length(), &result[0], result.size());
4241         (void)D3DPERF_BeginEvent(D3DCOLOR_ARGB(1, 0, 1, 0), &result[0]);
4242     }
4243 
4244     //---------------------------------------------------------------------
endProfileEvent(void)4245     void D3D9RenderSystem::endProfileEvent( void )
4246     {
4247         (void)D3DPERF_EndEvent();
4248     }
4249 
4250     //---------------------------------------------------------------------
markProfileEvent(const String & eventName)4251     void D3D9RenderSystem::markProfileEvent( const String &eventName )
4252     {
4253         if( eventName.empty() )
4254             return;
4255 
4256         vector<wchar_t>::type result(eventName.length() + 1, '\0');
4257         (void)MultiByteToWideChar(CP_ACP, 0, eventName.data(), eventName.length(), &result[0], result.size());
4258         (void)D3DPERF_SetMarker(D3DCOLOR_ARGB(1, 0, 1, 0), &result[0]);
4259     }
4260 
4261 	//---------------------------------------------------------------------
getSamplerId(size_t unit)4262 	DWORD D3D9RenderSystem::getSamplerId(size_t unit)
4263 	{
4264 		return static_cast<DWORD>(unit) +
4265 			((mTexStageDesc[unit].pVertexTex == NULL) ? 0 : D3DVERTEXTEXTURESAMPLER0);
4266 	}
4267 
4268 	//---------------------------------------------------------------------
notifyOnDeviceLost(D3D9Device * device)4269 	void D3D9RenderSystem::notifyOnDeviceLost(D3D9Device* device)
4270 	{
4271 		StringStream ss;
4272 
4273 		ss << "D3D9 Device 0x[" << device->getD3D9Device() << "] entered lost state";
4274 		LogManager::getSingleton().logMessage(ss.str());
4275 
4276 		fireDeviceEvent(device, "DeviceLost");
4277 
4278 	}
4279 
4280 	//---------------------------------------------------------------------
notifyOnDeviceReset(D3D9Device * device)4281 	void D3D9RenderSystem::notifyOnDeviceReset(D3D9Device* device)
4282 	{
4283 		// Reset state attributes.
4284 		mVertexProgramBound = false;
4285 		mFragmentProgramBound = false;
4286 		mLastVertexSourceCount = 0;
4287 
4288 
4289 		// Force all compositors to reconstruct their internal resources
4290 		// render textures will have been changed without their knowledge
4291 		CompositorManager::getSingleton()._reconstructAllCompositorResources();
4292 
4293 		// Restore previous active device.
4294 
4295 		// Invalidate active view port.
4296 		mActiveViewport = NULL;
4297 
4298 		StringStream ss;
4299 
4300 		// Reset the texture stages, they will need to be rebound
4301 		for (size_t i = 0; i < OGRE_MAX_TEXTURE_LAYERS; ++i)
4302 			_setTexture(i, false, TexturePtr());
4303 
4304 		LogManager::getSingleton().logMessage("!!! Direct3D Device successfully restored.");
4305 
4306 		ss << "D3D9 device: 0x[" << device->getD3D9Device() << "] was reset";
4307 		LogManager::getSingleton().logMessage(ss.str());
4308 
4309 		fireDeviceEvent(device, "DeviceRestored");
4310 
4311 	}
4312 
4313 	//---------------------------------------------------------------------
determineFSAASettings(IDirect3DDevice9 * d3d9Device,size_t fsaa,const String & fsaaHint,D3DFORMAT d3dPixelFormat,bool fullScreen,D3DMULTISAMPLE_TYPE * outMultisampleType,DWORD * outMultisampleQuality)4314 	void D3D9RenderSystem::determineFSAASettings(IDirect3DDevice9* d3d9Device,
4315 		size_t fsaa, const String& fsaaHint, D3DFORMAT d3dPixelFormat,
4316 		bool fullScreen, D3DMULTISAMPLE_TYPE *outMultisampleType, DWORD *outMultisampleQuality)
4317 	{
4318 		bool ok = false;
4319 		bool qualityHint = fsaaHint.find("Quality") != String::npos;
4320 		size_t origFSAA = fsaa;
4321 
4322 		D3D9DriverList* driverList = getDirect3DDrivers();
4323 		D3D9Driver* deviceDriver = mActiveD3DDriver;
4324 		D3D9Device* device = mDeviceManager->getDeviceFromD3D9Device(d3d9Device);
4325 
4326 		for (uint i = 0; i < driverList->count(); ++i)
4327 		{
4328 			D3D9Driver* currDriver = driverList->item(i);
4329 
4330 			if (currDriver->getAdapterNumber() == device->getAdapterNumber())
4331 			{
4332 				deviceDriver = currDriver;
4333 				break;
4334 			}
4335 		}
4336 
4337 		bool tryCSAA = false;
4338 		// NVIDIA, prefer CSAA if available for 8+
4339 		// it would be tempting to use getCapabilities()->getVendor() == GPU_NVIDIA but
4340 		// if this is the first window, caps will not be initialised yet
4341 		if (deviceDriver->getAdapterIdentifier().VendorId == 0x10DE &&
4342 			fsaa >= 8)
4343 		{
4344 			tryCSAA	 = true;
4345 		}
4346 
4347 		while (!ok)
4348 		{
4349 			// Deal with special cases
4350 			if (tryCSAA)
4351 			{
4352 				// see http://developer.nvidia.com/object/coverage-sampled-aa.html
4353 				switch(fsaa)
4354 				{
4355 				case 8:
4356 					if (qualityHint)
4357 					{
4358 						*outMultisampleType = D3DMULTISAMPLE_8_SAMPLES;
4359 						*outMultisampleQuality = 0;
4360 					}
4361 					else
4362 					{
4363 						*outMultisampleType = D3DMULTISAMPLE_4_SAMPLES;
4364 						*outMultisampleQuality = 2;
4365 					}
4366 					break;
4367 				case 16:
4368 					if (qualityHint)
4369 					{
4370 						*outMultisampleType = D3DMULTISAMPLE_8_SAMPLES;
4371 						*outMultisampleQuality = 2;
4372 					}
4373 					else
4374 					{
4375 						*outMultisampleType = D3DMULTISAMPLE_4_SAMPLES;
4376 						*outMultisampleQuality = 4;
4377 					}
4378 					break;
4379 				}
4380 			}
4381 			else // !CSAA
4382 			{
4383 				*outMultisampleType = (D3DMULTISAMPLE_TYPE)fsaa;
4384 				*outMultisampleQuality = 0;
4385 			}
4386 
4387 
4388 			HRESULT hr;
4389 			DWORD outQuality;
4390 			hr = mD3D->CheckDeviceMultiSampleType(
4391 				deviceDriver->getAdapterNumber(),
4392 				D3DDEVTYPE_HAL,
4393 				d3dPixelFormat,
4394 				fullScreen,
4395 				*outMultisampleType,
4396 				&outQuality);
4397 
4398 			if (SUCCEEDED(hr) &&
4399 				(!tryCSAA || outQuality > *outMultisampleQuality))
4400 			{
4401 				ok = true;
4402 			}
4403 			else
4404 			{
4405 				// downgrade
4406 				if (tryCSAA && fsaa == 8)
4407 				{
4408 					// for CSAA, we'll try downgrading with quality mode at all samples.
4409 					// then try without quality, then drop CSAA
4410 					if (qualityHint)
4411 					{
4412 						// drop quality first
4413 						qualityHint = false;
4414 					}
4415 					else
4416 					{
4417 						// drop CSAA entirely
4418 						tryCSAA = false;
4419 					}
4420 					// return to original requested samples
4421 					fsaa = origFSAA;
4422 				}
4423 				else
4424 				{
4425 					// drop samples
4426 					--fsaa;
4427 
4428 					OgreAssert(fsaa > 0, "FSAA underflow: infinite loop (this should never happen)");
4429 
4430 					if (fsaa <= 1)
4431 					{
4432 						// ran out of options, no FSAA
4433 						fsaa = 0;
4434 						ok = true;
4435 
4436 						*outMultisampleType = D3DMULTISAMPLE_NONE;
4437 						*outMultisampleQuality = 0;
4438 					}
4439 				}
4440 			}
4441 
4442 		} // while !ok
4443 	}
4444 
4445 	//---------------------------------------------------------------------
fireDeviceEvent(D3D9Device * device,const String & name)4446 	void D3D9RenderSystem::fireDeviceEvent( D3D9Device* device, const String & name )
4447 	{
4448 		NameValuePairList params;
4449 		params["D3DDEVICE"] =  StringConverter::toString((size_t)device->getD3D9Device());
4450 		params["DEVICE_ADAPTER_NUMBER"] =  StringConverter::toString(device->getAdapterNumber());
4451 
4452 		fireEvent(name, &params);
4453 	}
4454 }
4455