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 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 -----------------------------------------------------------------------------
26 */
27 #include "OgreShaderGenerator.h"
28 #include "OgreShaderProgram.h"
29 #include "OgreShaderProgramManager.h"
30 #include "OgreShaderFFPRenderStateBuilder.h"
31 #include "OgreShaderRenderState.h"
32 #include "OgreMaterialManager.h"
33 #include "OgreTechnique.h"
34 #include "OgreSceneManager.h"
35 #include "OgreViewport.h"
36 #include "OgreShaderExPerPixelLighting.h"
37 #include "OgreShaderExNormalMapLighting.h"
38 #include "OgreShaderExIntegratedPSSM3.h"
39 #include "OgreShaderExLayeredBlending.h"
40 #include "OgreShaderExHardwareSkinning.h"
41 #include "OgreShaderMaterialSerializerListener.h"
42 #include "OgreShaderProgramWriterManager.h"
43 #include "OgreGpuProgramManager.h"
44 #include "OgreHighLevelGpuProgramManager.h"
45 #include "OgreShaderExTextureAtlasSampler.h"
46 #include "OgreShaderExTriplanarTexturing.h"
47 
48 namespace Ogre {
49 
50 const String cBlankString;
51 
52 //-----------------------------------------------------------------------
53 template<>
54 RTShader::ShaderGenerator* Singleton<RTShader::ShaderGenerator>::msSingleton = 0;
55 
56 namespace RTShader {
57 
58 String ShaderGenerator::DEFAULT_SCHEME_NAME		= "ShaderGeneratorDefaultScheme";
59 String GENERATED_SHADERS_GROUP_NAME				= "ShaderGeneratorResourceGroup";
60 String ShaderGenerator::SGPass::UserKey			= "SGPass";
61 String ShaderGenerator::SGTechnique::UserKey	= "SGTechnique";
62 
63 //-----------------------------------------------------------------------
getSingletonPtr()64 ShaderGenerator* ShaderGenerator::getSingletonPtr()
65 {
66 	return msSingleton;
67 }
68 
69 //-----------------------------------------------------------------------
getSingleton()70 ShaderGenerator& ShaderGenerator::getSingleton()
71 {
72 	assert( msSingleton );
73 	return ( *msSingleton );
74 }
75 
76 //-----------------------------------------------------------------------------
ShaderGenerator()77 ShaderGenerator::ShaderGenerator()
78 {
79 	mProgramWriterManager		= NULL;
80 	mProgramManager				= NULL;
81 	mFFPRenderStateBuilder		= NULL;
82 	mActiveSceneMgr				= NULL;
83 	mRenderObjectListener		= NULL;
84 	mSceneManagerListener		= NULL;
85 	mScriptTranslatorManager	= NULL;
86 	mMaterialSerializerListener	= NULL;
87 	mActiveViewportValid		= false;
88 	mLightCount[0]				= 0;
89 	mLightCount[1]				= 0;
90 	mLightCount[2]				= 0;
91 	mVSOutputCompactPolicy		= VSOCP_LOW;
92 	mCreateShaderOverProgrammablePass = false;
93     mIsFinalizing               = false;
94     mFSLayer                    = 0;
95 	mShaderLanguage             = "";
96 
97 	HighLevelGpuProgramManager& hmgr = HighLevelGpuProgramManager::getSingleton();
98 
99 	if (hmgr.isLanguageSupported("glsles"))
100 	{
101 		mShaderLanguage	= "glsles";
102 	}
103 	else if (hmgr.isLanguageSupported("cg"))
104 	{
105 		mShaderLanguage	= "cg";
106 	}
107 	else if (hmgr.isLanguageSupported("glsl"))
108 	{
109 		mShaderLanguage	= "glsl";
110 	}
111 	else if (hmgr.isLanguageSupported("hlsl"))
112 	{
113 		mShaderLanguage	= "hlsl";
114 	}
115 	else
116 	{
117 		// ASSAF: This is disabled for now - to stop an exception on the iOS
118 		// when running with the OpenGL ES 1.x that doesn't support shaders...
119 		/*
120 		OGRE_EXCEPT( Exception::ERR_INTERNAL_ERROR,
121 			"ShaderGenerator creation error: None of the profiles is supported.",
122 			"ShaderGenerator::ShaderGenerator" );
123 
124 		*/
125 		mShaderLanguage	= "cg"; // HACK for now
126 	}
127 
128 	setVertexShaderProfiles("gpu_vp gp4vp vp40 vp30 arbvp1 vs_4_0 vs_4_0_level_9_3 vs_4_0_level_9_1 vs_3_0 vs_2_x vs_2_a vs_2_0 vs_1_1");
129 	setFragmentShaderProfiles("ps_4_0 ps_4_0_level_9_3 ps_4_0_level_9_1 ps_3_x ps_3_0 fp40 fp30 fp20 arbfp1 ps_2_x ps_2_a ps_2_b ps_2_0 ps_1_4 ps_1_3 ps_1_2 ps_1_1");
130 }
131 
132 //-----------------------------------------------------------------------------
~ShaderGenerator()133 ShaderGenerator::~ShaderGenerator()
134 {
135 
136 }
137 
138 //-----------------------------------------------------------------------------
initialize()139 bool ShaderGenerator::initialize()
140 {
141 	if (msSingleton == NULL)
142 	{
143 		msSingleton = OGRE_NEW ShaderGenerator;
144 		if (false == msSingleton->_initialize())
145 		{
146 			OGRE_DELETE msSingleton;
147 			msSingleton = NULL;
148 			return false;
149 		}
150 	}
151 
152 	return true;
153 }
154 
155 //-----------------------------------------------------------------------------
_initialize()156 bool ShaderGenerator::_initialize()
157 {
158     OGRE_LOCK_AUTO_MUTEX;
159 
160 	// Allocate program writer manager.
161 	mProgramWriterManager = OGRE_NEW ProgramWriterManager;
162 
163 	// Allocate program manager.
164 	mProgramManager			= OGRE_NEW ProgramManager;
165 
166 	// Allocate and initialize FFP render state builder.
167 #ifdef RTSHADER_SYSTEM_BUILD_CORE_SHADERS
168 	mFFPRenderStateBuilder	= OGRE_NEW FFPRenderStateBuilder;
169 	if (false == mFFPRenderStateBuilder->initialize())
170 		return false;
171 #endif
172 
173 	// Create extensions factories.
174 	createSubRenderStateExFactories();
175 
176 	// Allocate script translator manager.
177 	mScriptTranslatorManager = OGRE_NEW SGScriptTranslatorManager(this);
178 	ScriptCompilerManager::getSingleton().addTranslatorManager(mScriptTranslatorManager);
179 
180 	addCustomScriptTranslator("rtshader_system", &mCoreScriptTranslator);
181 
182 	// Create the default scheme.
183 	createScheme(DEFAULT_SCHEME_NAME);
184 
185 	return true;
186 }
187 
188 
189 
190 //-----------------------------------------------------------------------------
createSubRenderStateExFactories()191 void ShaderGenerator::createSubRenderStateExFactories()
192 {
193 #ifdef RTSHADER_SYSTEM_BUILD_EXT_SHADERS
194     OGRE_LOCK_AUTO_MUTEX;
195 
196 	SubRenderStateFactory* curFactory;
197 
198     // check if we are running an old shader level in d3d11
199     bool d3d11AndLowProfile = ( (GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0_level_9_1") ||
200         GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0_level_9_3"))
201         && !GpuProgramManager::getSingleton().isSyntaxSupported("vs_4_0"));
202     if(!d3d11AndLowProfile)
203     {
204         curFactory = OGRE_NEW PerPixelLightingFactory;
205         addSubRenderStateFactory(curFactory);
206         mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
207 
208         curFactory = OGRE_NEW NormalMapLightingFactory;
209         addSubRenderStateFactory(curFactory);
210         mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
211 
212         curFactory = OGRE_NEW IntegratedPSSM3Factory;
213         addSubRenderStateFactory(curFactory);
214         mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
215 
216         curFactory = OGRE_NEW LayeredBlendingFactory;
217         addSubRenderStateFactory(curFactory);
218         mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
219 
220         curFactory = OGRE_NEW HardwareSkinningFactory;
221         addSubRenderStateFactory(curFactory);
222         mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
223     }
224 
225 	curFactory = OGRE_NEW TextureAtlasSamplerFactory;
226 	addSubRenderStateFactory(curFactory);
227 	mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
228 
229 	curFactory = OGRE_NEW TriplanarTexturingFactory;
230 	addSubRenderStateFactory(curFactory);
231 	mSubRenderStateExFactories[curFactory->getType()] = (curFactory);
232 #endif
233 }
234 
235 //-----------------------------------------------------------------------------
destroy()236 void ShaderGenerator::destroy()
237 {
238 	if (msSingleton != NULL)
239 	{
240 		msSingleton->_destroy();
241 
242 		OGRE_DELETE msSingleton;
243 		msSingleton = NULL;
244 	}
245 }
246 
247 //-----------------------------------------------------------------------------
_destroy()248 void ShaderGenerator::_destroy()
249 {
250     OGRE_LOCK_AUTO_MUTEX;
251 
252     mIsFinalizing = true;
253 
254 	// Delete technique entries.
255 	for (SGTechniqueMapIterator itTech = mTechniqueEntriesMap.begin(); itTech != mTechniqueEntriesMap.end(); ++itTech)
256 	{
257 		OGRE_DELETE (itTech->second);
258 	}
259 	mTechniqueEntriesMap.clear();
260 
261 	// Delete material entries.
262 	for (SGMaterialIterator itMat = mMaterialEntriesMap.begin(); itMat != mMaterialEntriesMap.end(); ++itMat)
263 	{
264 		OGRE_DELETE (itMat->second);
265 	}
266 	mMaterialEntriesMap.clear();
267 
268 	// Delete scheme entries.
269 	for (SGSchemeIterator itScheme = mSchemeEntriesMap.begin(); itScheme != mSchemeEntriesMap.end(); ++itScheme)
270 	{
271 		OGRE_DELETE (itScheme->second);
272 	}
273 	mSchemeEntriesMap.clear();
274 
275 	// Destroy extensions factories.
276 	destroySubRenderStateExFactories();
277 
278 #ifdef RTSHADER_SYSTEM_BUILD_CORE_SHADERS
279 	// Delete FFP Emulator.
280 	if (mFFPRenderStateBuilder != NULL)
281 	{
282 		mFFPRenderStateBuilder->destroy();
283 		OGRE_DELETE mFFPRenderStateBuilder;
284 		mFFPRenderStateBuilder = NULL;
285 	}
286 #endif
287 
288 	// Delete Program manager.
289 	if (mProgramManager != NULL)
290 	{
291 		OGRE_DELETE mProgramManager;
292 		mProgramManager = NULL;
293 	}
294 
295 	// Delete Program writer manager.
296 	if(mProgramWriterManager != NULL)
297 	{
298 		OGRE_DELETE mProgramWriterManager;
299 		mProgramWriterManager = NULL;
300 	}
301 
302 	removeCustomScriptTranslator("rtshader_system");
303 
304 	// Delete script translator manager.
305 	if (mScriptTranslatorManager != NULL)
306 	{
307 		ScriptCompilerManager::getSingleton().removeTranslatorManager(mScriptTranslatorManager);
308 		OGRE_DELETE mScriptTranslatorManager;
309 		mScriptTranslatorManager = NULL;
310 	}
311 
312 	// Delete material Serializer listener.
313 	if (mMaterialSerializerListener != NULL)
314 	{
315 		OGRE_DELETE mMaterialSerializerListener;
316 		mMaterialSerializerListener = NULL;
317 	}
318 
319 	// Remove all scene managers.
320 	while (mSceneManagerMap.empty() == false)
321 	{
322 		SceneManagerIterator itSceneMgr    = mSceneManagerMap.begin();
323 
324 		removeSceneManager(itSceneMgr->second);
325 	}
326 
327 	// Delete render object listener.
328 	if (mRenderObjectListener != NULL)
329 	{
330 		OGRE_DELETE mRenderObjectListener;
331 		mRenderObjectListener = NULL;
332 	}
333 
334 	// Delete scene manager listener.
335 	if (mSceneManagerListener != NULL)
336 	{
337 		OGRE_DELETE mSceneManagerListener;
338 		mSceneManagerListener = NULL;
339 	}
340 }
341 
342 //-----------------------------------------------------------------------------
destroySubRenderStateExFactories()343 void ShaderGenerator::destroySubRenderStateExFactories()
344 {
345     OGRE_LOCK_AUTO_MUTEX;
346 
347 	SubRenderStateFactoryIterator it;
348 
349 	for (it = mSubRenderStateExFactories.begin(); it != mSubRenderStateExFactories.end(); ++it)
350 	{
351 		removeSubRenderStateFactory(it->second);
352 		OGRE_DELETE it->second;
353 	}
354 	mSubRenderStateExFactories.clear();
355 }
356 
357 //-----------------------------------------------------------------------------
addSubRenderStateFactory(SubRenderStateFactory * factory)358 void ShaderGenerator::addSubRenderStateFactory(SubRenderStateFactory* factory)
359 {
360     OGRE_LOCK_AUTO_MUTEX;
361 
362 	SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.find(factory->getType());
363 
364 	if (itFind != mSubRenderStateFactories.end())
365 	{
366 		OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
367 			"A factory of type '" + factory->getType() + "' already exists.",
368 			"ShaderGenerator::addSubRenderStateFactory");
369 	}
370 
371 	mSubRenderStateFactories[factory->getType()] = factory;
372 }
373 
374 //-----------------------------------------------------------------------------
getNumSubRenderStateFactories() const375 size_t ShaderGenerator::getNumSubRenderStateFactories() const
376 {
377 	return mSubRenderStateFactories.size();
378 }
379 
380 
381 //-----------------------------------------------------------------------------
getSubRenderStateFactory(size_t index)382 SubRenderStateFactory*  ShaderGenerator::getSubRenderStateFactory(size_t index)
383 {
384 	{
385             OGRE_LOCK_AUTO_MUTEX;
386 
387 		SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.begin();
388 		for(; index != 0 && itFind != mSubRenderStateFactories.end(); --index , ++itFind);
389 
390 		if (itFind != mSubRenderStateFactories.end())
391 		{
392 			return itFind->second;
393 		}
394 	}
395 
396 	OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
397 		"A factory on index " + StringConverter::toString(index) + " does not exist.",
398 		"ShaderGenerator::addSubRenderStateFactory");
399 
400 	return NULL;
401 }
402 //-----------------------------------------------------------------------------
getSubRenderStateFactory(const String & type)403 SubRenderStateFactory* ShaderGenerator::getSubRenderStateFactory(const String& type)
404 {
405     OGRE_LOCK_AUTO_MUTEX;
406 
407 	SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.find(type);
408 	return (itFind != mSubRenderStateFactories.end()) ? itFind->second : NULL;
409 }
410 
411 //-----------------------------------------------------------------------------
removeSubRenderStateFactory(SubRenderStateFactory * factory)412 void ShaderGenerator::removeSubRenderStateFactory(SubRenderStateFactory* factory)
413 {
414     OGRE_LOCK_AUTO_MUTEX;
415 
416 	SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.find(factory->getType());
417 
418 	if (itFind != mSubRenderStateFactories.end())
419 		mSubRenderStateFactories.erase(itFind);
420 
421 }
422 
423 //-----------------------------------------------------------------------------
createSubRenderState(const String & type)424 SubRenderState*	ShaderGenerator::createSubRenderState(const String& type)
425 {
426     OGRE_LOCK_AUTO_MUTEX;
427 
428 	SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.find(type);
429 
430 	if (itFind != mSubRenderStateFactories.end())
431 		return itFind->second->createInstance();
432 
433 
434 	OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
435 		"A factory of type '" + type + "' doesn't exists.",
436 		"ShaderGenerator::createSubRenderState");
437 
438 	return NULL;
439 }
440 
441 //-----------------------------------------------------------------------------
destroySubRenderState(SubRenderState * subRenderState)442 void ShaderGenerator::destroySubRenderState(SubRenderState* subRenderState)
443 {
444     OGRE_LOCK_AUTO_MUTEX;
445 
446 	SubRenderStateFactoryIterator itFind = mSubRenderStateFactories.find(subRenderState->getType());
447 
448 	if (itFind != mSubRenderStateFactories.end())
449 	{
450 		 itFind->second->destroyInstance(subRenderState);
451 	}
452 }
453 
454 //-----------------------------------------------------------------------------
createSubRenderState(ScriptCompiler * compiler,PropertyAbstractNode * prop,Pass * pass,SGScriptTranslator * translator)455 SubRenderState*	ShaderGenerator::createSubRenderState(ScriptCompiler* compiler,
456 													  PropertyAbstractNode* prop, Pass* pass, SGScriptTranslator* translator)
457 {
458     OGRE_LOCK_AUTO_MUTEX;
459 
460 	SubRenderStateFactoryIterator it = mSubRenderStateFactories.begin();
461 	SubRenderStateFactoryIterator itEnd = mSubRenderStateFactories.end();
462 	SubRenderState* subRenderState = NULL;
463 
464 	while (it != itEnd)
465 	{
466 		subRenderState = it->second->createInstance(compiler, prop, pass, translator);
467 		if (subRenderState != NULL)
468 			break;
469 		++it;
470 	}
471 
472 	return subRenderState;
473 }
474 
475 
476 //-----------------------------------------------------------------------------
createSubRenderState(ScriptCompiler * compiler,PropertyAbstractNode * prop,TextureUnitState * texState,SGScriptTranslator * translator)477 SubRenderState*	ShaderGenerator::createSubRenderState(ScriptCompiler* compiler,
478 													  PropertyAbstractNode* prop, TextureUnitState* texState, SGScriptTranslator* translator)
479 {
480     OGRE_LOCK_AUTO_MUTEX;
481 
482 	SubRenderStateFactoryIterator it = mSubRenderStateFactories.begin();
483 	SubRenderStateFactoryIterator itEnd = mSubRenderStateFactories.end();
484 	SubRenderState* subRenderState = NULL;
485 
486 	while (it != itEnd)
487 	{
488 		subRenderState = it->second->createInstance(compiler, prop, texState, translator);
489 		if (subRenderState != NULL)
490 			break;
491 		++it;
492 	}
493 
494 	return subRenderState;
495 }
496 
497 //-----------------------------------------------------------------------------
createScheme(const String & schemeName)498 void ShaderGenerator::createScheme(const String& schemeName)
499 {
500     OGRE_LOCK_AUTO_MUTEX;
501 
502 	SGSchemeIterator itFind = mSchemeEntriesMap.find(schemeName);
503 	SGScheme* schemeEntry   = NULL;
504 
505 	if (itFind == mSchemeEntriesMap.end())
506 	{
507 		schemeEntry = OGRE_NEW SGScheme(schemeName);
508 		mSchemeEntriesMap[schemeName] = schemeEntry;
509 	}
510 }
511 
512 //-----------------------------------------------------------------------------
getRenderState(const String & schemeName)513 RenderState* ShaderGenerator::getRenderState(const String& schemeName)
514 {
515     OGRE_LOCK_AUTO_MUTEX;
516 
517 	SGSchemeIterator itFind = mSchemeEntriesMap.find(schemeName);
518 
519 	if (itFind == mSchemeEntriesMap.end())
520 	{
521 		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
522 			"A scheme named'" + schemeName + "' doesn't exists.",
523 			"ShaderGenerator::getRenderState");
524 	}
525 
526 	return itFind->second->getRenderState();
527 }
528 
529 //-----------------------------------------------------------------------------
hasRenderState(const String & schemeName) const530 bool ShaderGenerator::hasRenderState(const String& schemeName) const
531 {
532     OGRE_LOCK_AUTO_MUTEX;
533 
534 	SGSchemeConstIterator itFind = mSchemeEntriesMap.find(schemeName);
535 	return itFind != mSchemeEntriesMap.end();
536 }
537 
538 //-----------------------------------------------------------------------------
createOrRetrieveRenderState(const String & schemeName)539 ShaderGenerator::RenderStateCreateOrRetrieveResult ShaderGenerator::createOrRetrieveRenderState(const String& schemeName)
540 {
541 	SchemeCreateOrRetrieveResult res = createOrRetrieveScheme(schemeName);
542 	return RenderStateCreateOrRetrieveResult(res.first->getRenderState(),res.second);
543 }
544 
545 //-----------------------------------------------------------------------------
createOrRetrieveScheme(const String & schemeName)546 ShaderGenerator::SchemeCreateOrRetrieveResult ShaderGenerator::createOrRetrieveScheme(const String& schemeName)
547 {
548     OGRE_LOCK_AUTO_MUTEX;
549 
550 	bool wasCreated = false;
551 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(schemeName);
552 	SGScheme* schemeEntry = NULL;
553 
554 	if (itScheme == mSchemeEntriesMap.end())
555 	{
556 		schemeEntry = OGRE_NEW SGScheme(schemeName);
557 		mSchemeEntriesMap.insert(SGSchemeMap::value_type(schemeName, schemeEntry));
558 		wasCreated = true;
559 	}
560 	else
561 	{
562 		schemeEntry = itScheme->second;
563 	}
564 
565 	return SchemeCreateOrRetrieveResult(schemeEntry, wasCreated);
566 }
567 
568 //-----------------------------------------------------------------------------
getRenderState(const String & schemeName,const String & materialName,unsigned short passIndex)569 RenderState* ShaderGenerator::getRenderState(const String& schemeName,
570 											 const String& materialName,
571 											 unsigned short passIndex)
572 {
573 	return getRenderState(schemeName, materialName,
574 		ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME, passIndex);
575 }
576 //-----------------------------------------------------------------------------
getRenderState(const String & schemeName,const String & materialName,const String & groupName,unsigned short passIndex)577 RenderState* ShaderGenerator::getRenderState(const String& schemeName,
578 									 const String& materialName,
579 									 const String& groupName,
580 									 unsigned short passIndex)
581 {
582     OGRE_LOCK_AUTO_MUTEX;
583 
584 	SGSchemeIterator itFind = mSchemeEntriesMap.find(schemeName);
585 
586 	if (itFind == mSchemeEntriesMap.end())
587 	{
588 		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
589 			"A scheme named'" + schemeName + "' doesn't exists.",
590 			"ShaderGenerator::getRenderState");
591 	}
592 
593 	return itFind->second->getRenderState(materialName, groupName, passIndex);
594 }
595 
596 //-----------------------------------------------------------------------------
addSceneManager(SceneManager * sceneMgr)597 void ShaderGenerator::addSceneManager(SceneManager* sceneMgr)
598 {
599 	// Make sure this scene manager not exists in the map.
600 	SceneManagerIterator itFind = mSceneManagerMap.find(sceneMgr->getName());
601 
602 	if (itFind != mSceneManagerMap.end())
603 		return;
604 
605 	if (mRenderObjectListener == NULL)
606 		mRenderObjectListener = OGRE_NEW SGRenderObjectListener(this);
607 
608 	sceneMgr->addRenderObjectListener(mRenderObjectListener);
609 
610 	if (mSceneManagerListener == NULL)
611 		mSceneManagerListener = OGRE_NEW SGSceneManagerListener(this);
612 
613 	sceneMgr->addListener(mSceneManagerListener);
614 
615 	mSceneManagerMap[sceneMgr->getName()] = sceneMgr;
616 
617 	// Update the active scene manager.
618 	if (mActiveSceneMgr == NULL)
619 		mActiveSceneMgr = sceneMgr;
620 }
621 
622 //-----------------------------------------------------------------------------
removeSceneManager(SceneManager * sceneMgr)623 void ShaderGenerator::removeSceneManager(SceneManager* sceneMgr)
624 {
625 	// Make sure this scene manager exists in the map.
626 	SceneManagerIterator itFind = mSceneManagerMap.find(sceneMgr->getName());
627 
628 	if (itFind != mSceneManagerMap.end())
629 	{
630 		itFind->second->removeRenderObjectListener(mRenderObjectListener);
631 		itFind->second->removeListener(mSceneManagerListener);
632 
633 		mSceneManagerMap.erase(itFind);
634 
635 		// Update the active scene manager.
636 		if (mActiveSceneMgr == sceneMgr)
637 			mActiveSceneMgr = NULL;
638 	}
639 }
640 
641 //-----------------------------------------------------------------------------
getActiveSceneManager()642 SceneManager* ShaderGenerator::getActiveSceneManager()
643 {
644 	return mActiveSceneMgr;
645 }
646 
647 //-----------------------------------------------------------------------------
setVertexShaderProfiles(const String & vertexShaderProfiles)648 void ShaderGenerator::setVertexShaderProfiles(const String& vertexShaderProfiles)
649 {
650 	mVertexShaderProfiles = vertexShaderProfiles;
651 	mVertexShaderProfilesList = StringUtil::split(vertexShaderProfiles);
652 }
653 //-----------------------------------------------------------------------------
setFragmentShaderProfiles(const String & fragmentShaderProfiles)654 void ShaderGenerator::setFragmentShaderProfiles(const String& fragmentShaderProfiles)
655 {
656 	mFragmentShaderProfiles = fragmentShaderProfiles;
657 	mFragmentShaderProfilesList = StringUtil::split(fragmentShaderProfiles);
658 }
659 
660 //-----------------------------------------------------------------------------
hasShaderBasedTechnique(const String & materialName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName) const661 bool ShaderGenerator::hasShaderBasedTechnique(const String& materialName,
662 											  const String& srcTechniqueSchemeName,
663 											  const String& dstTechniqueSchemeName) const
664 {
665 	return hasShaderBasedTechnique(materialName, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
666 		srcTechniqueSchemeName, dstTechniqueSchemeName);
667 }
668 //-----------------------------------------------------------------------------
hasShaderBasedTechnique(const String & materialName,const String & groupName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName) const669 bool ShaderGenerator::hasShaderBasedTechnique(const String& materialName,
670 												 const String& groupName,
671 												 const String& srcTechniqueSchemeName,
672 												 const String& dstTechniqueSchemeName) const
673 {
674     OGRE_LOCK_AUTO_MUTEX;
675 
676 	// Make sure material exists;
677 	if (false == MaterialManager::getSingleton().resourceExists(materialName))
678 		return false;
679 
680 
681 	SGMaterialConstIterator itMatEntry = findMaterialEntryIt(materialName, groupName);
682 
683 	// Check if technique already created.
684 	if (itMatEntry != mMaterialEntriesMap.end())
685 	{
686 		const SGTechniqueList& techniqueEntires = itMatEntry->second->getTechniqueList();
687 		SGTechniqueConstIterator itTechEntry = techniqueEntires.begin();
688 
689 		for (; itTechEntry != techniqueEntires.end(); ++itTechEntry)
690 		{
691 			// Check requested mapping already exists.
692 			if ((*itTechEntry)->getSourceTechnique()->getSchemeName() == srcTechniqueSchemeName &&
693 				(*itTechEntry)->getDestinationTechniqueSchemeName() == dstTechniqueSchemeName)
694 			{
695 				return true;
696 			}
697 		}
698 	}
699 	return false;
700 }
701 //-----------------------------------------------------------------------------
createShaderBasedTechnique(const String & materialName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName,bool overProgrammable)702 bool ShaderGenerator::createShaderBasedTechnique(const String& materialName,
703 												 const String& srcTechniqueSchemeName,
704 												 const String& dstTechniqueSchemeName,
705 												 bool overProgrammable)
706 {
707 	return createShaderBasedTechnique(materialName, ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
708 		srcTechniqueSchemeName, dstTechniqueSchemeName, overProgrammable);
709 }
710 //-----------------------------------------------------------------------------
createShaderBasedTechnique(const String & materialName,const String & groupName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName,bool overProgrammable)711 bool ShaderGenerator::createShaderBasedTechnique(const String& materialName,
712 												 const String& groupName,
713 												 const String& srcTechniqueSchemeName,
714 												 const String& dstTechniqueSchemeName,
715 												 bool overProgrammable)
716 {
717     OGRE_LOCK_AUTO_MUTEX;
718 
719 	// Make sure material exists.
720 	MaterialPtr srcMat = MaterialManager::getSingleton().getByName(materialName, groupName);
721 	if (srcMat.isNull() == true)
722 		return false;
723 
724 	// Update group name in case it is AUTODETECT_RESOURCE_GROUP_NAME
725 	const String& trueGroupName = srcMat->getGroup();
726 
727 	// Case the requested material belongs to different group and it is not AUTODETECT_RESOURCE_GROUP_NAME.
728 	if (trueGroupName != groupName &&
729 		groupName != ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
730 	{
731 		return false;
732 	}
733 
734 	SGMaterialIterator itMatEntry = findMaterialEntryIt(materialName, trueGroupName);
735 
736 	// Check if technique already created.
737 	if (itMatEntry != mMaterialEntriesMap.end())
738 	{
739 		const SGTechniqueList& techniqueEntires = itMatEntry->second->getTechniqueList();
740 		SGTechniqueConstIterator itTechEntry = techniqueEntires.begin();
741 
742 		for (; itTechEntry != techniqueEntires.end(); ++itTechEntry)
743 		{
744 			// Case the requested mapping already exists.
745 			if ((*itTechEntry)->getSourceTechnique()->getSchemeName() == srcTechniqueSchemeName &&
746 				(*itTechEntry)->getDestinationTechniqueSchemeName() == dstTechniqueSchemeName)
747 			{
748 				return true;
749 			}
750 
751 
752 			// Case a shader based technique with the same scheme name already defined based
753 			// on different source technique.
754 			// This state might lead to conflicts during shader generation - we prevent it by returning false here.
755 			else if ((*itTechEntry)->getDestinationTechniqueSchemeName() == dstTechniqueSchemeName)
756 			{
757 				return false;
758 			}
759 		}
760 	}
761 
762 	// No technique created -> check if one can be created from the given source technique scheme.
763 	Technique* srcTechnique = NULL;
764 	srcTechnique = findSourceTechnique(materialName, trueGroupName, srcTechniqueSchemeName, overProgrammable);
765 
766 	// No appropriate source technique found.
767 	if (srcTechnique == NULL)
768 	{
769 		return false;
770 	}
771 
772 
773 	// Create shader based technique from the given source technique.
774 	SGMaterial* matEntry = NULL;
775 
776 	if (itMatEntry == mMaterialEntriesMap.end())
777 	{
778 		matEntry = OGRE_NEW SGMaterial(materialName, trueGroupName);
779 		mMaterialEntriesMap.insert(SGMaterialMap::value_type(
780 			MatGroupPair(materialName, trueGroupName), matEntry));
781 	}
782 	else
783 	{
784 		matEntry = itMatEntry->second;
785 	}
786 
787 	// Create the new technique entry.
788 	SGTechnique* techEntry = OGRE_NEW SGTechnique(matEntry, srcTechnique, dstTechniqueSchemeName);
789 
790 
791 	// Add to material entry map.
792 	matEntry->getTechniqueList().push_back(techEntry);
793 
794 	// Add to all technique map.
795 	mTechniqueEntriesMap[techEntry] = techEntry;
796 
797 	// Add to scheme.
798 	SGScheme* schemeEntry = createOrRetrieveScheme(dstTechniqueSchemeName).first;
799 	schemeEntry->addTechniqueEntry(techEntry);
800 
801 	return true;
802 }
803 
804 //-----------------------------------------------------------------------------
removeShaderBasedTechnique(const String & materialName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName)805 bool ShaderGenerator::removeShaderBasedTechnique(const String& materialName,
806 												 const String& srcTechniqueSchemeName,
807 												 const String& dstTechniqueSchemeName)
808 {
809 	return removeShaderBasedTechnique(materialName,ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
810 		srcTechniqueSchemeName,dstTechniqueSchemeName);
811 }
812 //-----------------------------------------------------------------------------
removeShaderBasedTechnique(const String & materialName,const String & groupName,const String & srcTechniqueSchemeName,const String & dstTechniqueSchemeName)813 bool ShaderGenerator::removeShaderBasedTechnique(const String& materialName,
814 												 const String& groupName,
815 												 const String& srcTechniqueSchemeName,
816 												 const String& dstTechniqueSchemeName)
817 {
818     OGRE_LOCK_AUTO_MUTEX;
819 
820 	// Make sure scheme exists.
821 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(dstTechniqueSchemeName);
822 	SGScheme* schemeEntry = NULL;
823 
824 	if (itScheme == mSchemeEntriesMap.end())
825 		return false;
826 
827 	schemeEntry = itScheme->second;
828 
829 
830 
831 	// Find the material entry.
832 	SGMaterialIterator itMatEntry = findMaterialEntryIt(materialName,groupName);
833 
834 	// Case material not found.
835 	if (itMatEntry == mMaterialEntriesMap.end())
836 		return false;
837 
838 
839 	SGTechniqueList& matTechniqueEntires = itMatEntry->second->getTechniqueList();
840 	SGTechniqueIterator itTechEntry = matTechniqueEntires.begin();
841 	SGTechnique* dstTechnique = NULL;
842 
843 	// Remove destination technique entry from material techniques list.
844 	for (; itTechEntry != matTechniqueEntires.end(); ++itTechEntry)
845 	{
846 		if ((*itTechEntry)->getSourceTechnique()->getSchemeName() == srcTechniqueSchemeName &&
847 			(*itTechEntry)->getDestinationTechniqueSchemeName() == dstTechniqueSchemeName)
848 		{
849 			dstTechnique = *itTechEntry;
850 			matTechniqueEntires.erase(itTechEntry);
851 			break;
852 		}
853 	}
854 
855 	// Technique not found.
856 	if (dstTechnique == NULL)
857 		return false;
858 
859 	schemeEntry->removeTechniqueEntry(dstTechnique);
860 
861 	SGTechniqueMapIterator itTechMap = mTechniqueEntriesMap.find(dstTechnique);
862 
863 	if (itTechMap != mTechniqueEntriesMap.end())
864 		mTechniqueEntriesMap.erase(itTechMap);
865 
866 	OGRE_DELETE dstTechnique;
867 
868 	return true;
869 }
870 
871 //-----------------------------------------------------------------------------
removeAllShaderBasedTechniques(const String & materialName,const String & groupName)872 bool ShaderGenerator::removeAllShaderBasedTechniques(const String& materialName, const String& groupName)
873 {
874     OGRE_LOCK_AUTO_MUTEX;
875 
876 	// Find the material entry.
877 	SGMaterialIterator itMatEntry = findMaterialEntryIt(materialName, groupName);
878 
879 	// Case material not found.
880 	if (itMatEntry == mMaterialEntriesMap.end())
881 		return false;
882 
883 
884 	SGTechniqueList& matTechniqueEntires = itMatEntry->second->getTechniqueList();
885 
886 	// Remove all technique entries from material techniques list.
887 	while (matTechniqueEntires.empty() == false)
888 	{
889 		SGTechniqueIterator itTechEntry = matTechniqueEntires.begin();
890 
891 		removeShaderBasedTechnique(materialName, itMatEntry->first.second, (*itTechEntry)->getSourceTechnique()->getSchemeName(),
892 			(*itTechEntry)->getDestinationTechniqueSchemeName());
893 	}
894 
895 	OGRE_DELETE itMatEntry->second;
896 	mMaterialEntriesMap.erase(itMatEntry);
897 
898 	return true;
899 }
900 
901 //-----------------------------------------------------------------------------
cloneShaderBasedTechniques(const String & srcMaterialName,const String & srcGroupName,const String & dstMaterialName,const String & dstGroupName)902 bool ShaderGenerator::cloneShaderBasedTechniques(const String& srcMaterialName,
903 												 const String& srcGroupName,
904 												 const String& dstMaterialName,
905 												 const String& dstGroupName)
906 {
907     OGRE_LOCK_AUTO_MUTEX;
908 
909 	//
910 	// Check that both source and destination material exist
911 	//
912 
913 	// Make sure material exists.
914 	MaterialPtr srcMat = MaterialManager::getSingleton().getByName(srcMaterialName, srcGroupName);
915 	MaterialPtr dstMat = MaterialManager::getSingleton().getByName(dstMaterialName, dstGroupName);
916 	if ((srcMat.isNull() == true) || (dstMat.isNull() == true) || (srcMat == dstMat))
917 		return false;
918 
919 	// Update group name in case it is AUTODETECT_RESOURCE_GROUP_NAME
920 	const String& trueSrcGroupName = srcMat->getGroup();
921 	const String& trueDstGroupName = dstMat->getGroup();
922 
923 	// Case the requested material belongs to different group and it is not AUTODETECT_RESOURCE_GROUP_NAME.
924 	if ((trueSrcGroupName != srcGroupName && srcGroupName != ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME) ||
925 		(trueSrcGroupName != dstGroupName && dstGroupName != ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME))
926 	{
927 		return false;
928 	}
929 
930 	SGMaterialIterator itSrcMatEntry = findMaterialEntryIt(srcMaterialName, trueSrcGroupName);
931 
932 	//remove any techniques in the destination material so the new techniques may be copied
933 	removeAllShaderBasedTechniques(dstMaterialName, trueDstGroupName);
934 
935 	//
936 	//remove any techniques from the destination material which have RTSS associated schemes from
937 	//the source material. This code is performed in case the user performed a clone of a material
938 	//which has already generated RTSS techniques in the source material.
939 	//
940 
941 	//first gather the techniques to remove
942 	set<unsigned short>::type schemesToRemove;
943 	unsigned short techCount = srcMat->getNumTechniques();
944 	for(unsigned short ti = 0 ; ti < techCount ; ++ti)
945 	{
946 		Technique* pSrcTech = srcMat->getTechnique(ti);
947 		Pass* pSrcPass = pSrcTech->getNumPasses() > 0 ? pSrcTech->getPass(0) : NULL;
948 		if (pSrcPass)
949 		{
950 			const Any& passUserData = pSrcPass->getUserObjectBindings().getUserAny(SGPass::UserKey);
951 			if (!passUserData.isEmpty())
952 			{
953 				schemesToRemove.insert(pSrcTech->_getSchemeIndex());
954 			}
955 		}
956 	}
957 	//remove the techniques from the destination material
958 	techCount = dstMat->getNumTechniques();
959 	for(unsigned short ti = techCount - 1 ; ti != (unsigned short)-1 ; --ti)
960 	{
961 		Technique* pDstTech = dstMat->getTechnique(ti);
962 		if (schemesToRemove.find(pDstTech->_getSchemeIndex()) != schemesToRemove.end())
963 		{
964 			dstMat->removeTechnique(ti);
965 		}
966 	}
967 
968 	//
969 	// Clone the render states from source to destination
970 	//
971 
972 	// Check if RTSS techniques exist in the source material
973 	if (itSrcMatEntry != mMaterialEntriesMap.end())
974 	{
975 		const SGTechniqueList& techniqueEntires = itSrcMatEntry->second->getTechniqueList();
976 		SGTechniqueConstIterator itTechEntry = techniqueEntires.begin();
977 
978 		//Go over all rtss techniques in the source material
979 		for (; itTechEntry != techniqueEntires.end(); ++itTechEntry)
980 		{
981 			String srcFromTechniqueScheme = (*itTechEntry)->getSourceTechnique()->getSchemeName();
982 			String srcToTechniqueScheme = (*itTechEntry)->getDestinationTechniqueSchemeName();
983 
984 			//for every technique in the source material create a shader based technique in the
985 			//destination material
986 			if (createShaderBasedTechnique(dstMaterialName, trueDstGroupName, srcFromTechniqueScheme, srcToTechniqueScheme))
987 			{
988 				//check for custom render states in the source material
989 				unsigned short passCount =  (*itTechEntry)->getSourceTechnique()->getNumPasses();
990 				for(unsigned short pi = 0 ; pi < passCount ; ++pi)
991 				{
992 					if ((*itTechEntry)->hasRenderState(pi))
993 					{
994 						//copy the custom render state from the source material to the destination material
995 						RenderState* srcRenderState = (*itTechEntry)->getRenderState(pi);
996 						RenderState* dstRenderState = getRenderState(srcToTechniqueScheme, dstMaterialName, trueDstGroupName, pi);
997 
998 						const SubRenderStateList& srcSubRenderState =
999 							srcRenderState->getTemplateSubRenderStateList();
1000 
1001 						SubRenderStateList::const_iterator itSubState = srcSubRenderState.begin(),
1002 							itSubStateEnd = srcSubRenderState.end();
1003 						for(;itSubState != itSubStateEnd ; ++itSubState)
1004 						{
1005 							SubRenderState* srcSubState = *itSubState;
1006 							SubRenderState* dstSubState = createSubRenderState(srcSubState->getType());
1007 							(*dstSubState) = (*srcSubState);
1008 							dstRenderState->addTemplateSubRenderState(dstSubState);
1009 						}
1010 					}
1011 				}
1012 			}
1013 		}
1014 	}
1015 
1016 	return true;
1017 }
1018 
1019 //-----------------------------------------------------------------------------
removeAllShaderBasedTechniques()1020 void ShaderGenerator::removeAllShaderBasedTechniques()
1021 {
1022     OGRE_LOCK_AUTO_MUTEX;
1023 
1024 	while (mMaterialEntriesMap.size() > 0)
1025 	{
1026 		SGMaterialIterator itMatEntry = mMaterialEntriesMap.begin();
1027 
1028 		removeAllShaderBasedTechniques(itMatEntry->first.first, itMatEntry->first.second);
1029 	}
1030 }
1031 
1032 //-----------------------------------------------------------------------------
findSourceTechnique(const String & materialName,const String & groupName,const String & srcTechniqueSchemeName,bool allowProgrammable)1033  Technique* ShaderGenerator::findSourceTechnique(const String& materialName,
1034 				const String& groupName, const String& srcTechniqueSchemeName, bool allowProgrammable)
1035  {
1036      MaterialPtr mat = MaterialManager::getSingleton().getByName(materialName, groupName);
1037 	 Material::TechniqueIterator itMatTechniques = mat->getTechniqueIterator();
1038 
1039 
1040 	 // Find the source technique and make sure it is not programmable.
1041 	 while (itMatTechniques.hasMoreElements())
1042 	 {
1043 		 Technique* curTechnique = itMatTechniques.getNext();
1044 
1045 		 if (curTechnique->getSchemeName() == srcTechniqueSchemeName && (allowProgrammable || !isProgrammable(curTechnique)))
1046 		 {
1047 			 return curTechnique;
1048 		 }
1049 	 }
1050 
1051 	 return NULL;
1052  }
1053 
1054  //-----------------------------------------------------------------------------
isProgrammable(Technique * tech) const1055  bool ShaderGenerator::isProgrammable(Technique* tech) const
1056  {
1057 	 if (tech != NULL)
1058 	 {
1059 		 for (unsigned short i=0; i < tech->getNumPasses(); ++i)
1060 		 {
1061 			 if (tech->getPass(i)->isProgrammable() == true)
1062 			 {
1063 				 return true;
1064 			 }
1065 		 }
1066 	 }
1067 	 return false;
1068  }
1069 
1070 
1071 //-----------------------------------------------------------------------------
notifyRenderSingleObject(Renderable * rend,const Pass * pass,const AutoParamDataSource * source,const LightList * pLightList,bool suppressRenderStateChanges)1072  void ShaderGenerator::notifyRenderSingleObject(Renderable* rend,
1073 	 const Pass* pass,
1074 	 const AutoParamDataSource* source,
1075 	 const LightList* pLightList, bool suppressRenderStateChanges)
1076 {
1077 	if (mActiveViewportValid)
1078 	{
1079 		const Any& passUserData = pass->getUserObjectBindings().getUserAny(SGPass::UserKey);
1080 
1081 		if (passUserData.isEmpty())
1082 			return;
1083 
1084 		OGRE_LOCK_AUTO_MUTEX;
1085 
1086 		SGPass* passEntry = any_cast<SGPass*>(passUserData);
1087 
1088 		passEntry->notifyRenderSingleObject(rend, source, pLightList, suppressRenderStateChanges);
1089 
1090 	}
1091 }
1092 
1093 
1094 //-----------------------------------------------------------------------------
preFindVisibleObjects(SceneManager * source,SceneManager::IlluminationRenderStage irs,Viewport * v)1095 void ShaderGenerator::preFindVisibleObjects(SceneManager* source,
1096 											SceneManager::IlluminationRenderStage irs,
1097 											Viewport* v)
1098 {
1099     OGRE_LOCK_AUTO_MUTEX;
1100 
1101 	const String& curMaterialScheme = v->getMaterialScheme();
1102 
1103 	mActiveSceneMgr      = source;
1104 	mActiveViewportValid = validateScheme(curMaterialScheme);
1105 }
1106 
1107 //-----------------------------------------------------------------------------
invalidateScheme(const String & schemeName)1108 void ShaderGenerator::invalidateScheme(const String& schemeName)
1109 {
1110     OGRE_LOCK_AUTO_MUTEX;
1111 
1112 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(schemeName);
1113 
1114 	if (itScheme != mSchemeEntriesMap.end())
1115 		itScheme->second->invalidate();
1116 
1117 }
1118 
1119 //-----------------------------------------------------------------------------
validateScheme(const String & schemeName)1120 bool ShaderGenerator::validateScheme(const String& schemeName)
1121 {
1122     OGRE_LOCK_AUTO_MUTEX;
1123 
1124 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(schemeName);
1125 
1126 	// No such scheme exists.
1127 	if (itScheme == mSchemeEntriesMap.end())
1128 		return false;
1129 
1130 	itScheme->second->validate();
1131 
1132 	return true;
1133 }
1134 
1135 //-----------------------------------------------------------------------------
invalidateMaterial(const String & schemeName,const String & materialName,const String & groupName)1136 void ShaderGenerator::invalidateMaterial(const String& schemeName, const String& materialName, const String& groupName)
1137 {
1138     OGRE_LOCK_AUTO_MUTEX;
1139 
1140 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(schemeName);
1141 
1142 	if (itScheme != mSchemeEntriesMap.end())
1143 		itScheme->second->invalidate(materialName, groupName);
1144 }
1145 
1146 //-----------------------------------------------------------------------------
validateMaterial(const String & schemeName,const String & materialName,const String & groupName)1147 bool ShaderGenerator::validateMaterial(const String& schemeName, const String& materialName, const String& groupName)
1148 {
1149     OGRE_LOCK_AUTO_MUTEX;
1150 
1151 	SGSchemeIterator itScheme = mSchemeEntriesMap.find(schemeName);
1152 
1153 	// No such scheme exists.
1154 	if (itScheme == mSchemeEntriesMap.end())
1155 		return false;
1156 
1157 	return itScheme->second->validate(materialName, groupName);
1158 }
1159 
1160 //-----------------------------------------------------------------------------
getMaterialSerializerListener()1161 SGMaterialSerializerListener* ShaderGenerator::getMaterialSerializerListener()
1162 {
1163 	if (mMaterialSerializerListener == NULL)
1164 		mMaterialSerializerListener = OGRE_NEW SGMaterialSerializerListener;
1165 
1166 	return mMaterialSerializerListener;
1167 }
1168 
1169 //-----------------------------------------------------------------------------
flushShaderCache()1170 void ShaderGenerator::flushShaderCache()
1171 {
1172 	SGTechniqueMapIterator itTech = mTechniqueEntriesMap.begin();
1173 	SGTechniqueMapIterator itTechEnd = mTechniqueEntriesMap.end();
1174 
1175 	// Release all programs.
1176 	for (; itTech != itTechEnd; ++itTech)
1177 	{
1178 		itTech->second->releasePrograms();
1179 	}
1180 
1181 	ProgramManager::getSingleton().flushGpuProgramsCache();
1182 
1183 	SGSchemeIterator itScheme = mSchemeEntriesMap.begin();
1184 	SGSchemeIterator itSchemeEnd = mSchemeEntriesMap.end();
1185 
1186 	// Invalidate all schemes.
1187 	for (; itScheme != itSchemeEnd; ++itScheme)
1188 	{
1189 		itScheme->second->invalidate();
1190 	}
1191 }
1192 
1193 //-----------------------------------------------------------------------------
addCustomScriptTranslator(const String & key,ScriptTranslator * translator)1194 bool ShaderGenerator::addCustomScriptTranslator(const String& key, ScriptTranslator* translator)
1195 {
1196     OGRE_LOCK_AUTO_MUTEX;
1197 
1198 	SGScriptTranslatorIterator itFind = mScriptTranslatorsMap.find(key);
1199 
1200 	if (itFind != mScriptTranslatorsMap.end())
1201 		return false;
1202 
1203 	mScriptTranslatorsMap[key] = translator;
1204 
1205 	return true;
1206 }
1207 
1208 //-----------------------------------------------------------------------------
removeCustomScriptTranslator(const String & key)1209 bool ShaderGenerator::removeCustomScriptTranslator(const String& key)
1210 {
1211     OGRE_LOCK_AUTO_MUTEX;
1212 
1213 	SGScriptTranslatorIterator itFind = mScriptTranslatorsMap.find(key);
1214 
1215 	if (itFind == mScriptTranslatorsMap.end())
1216 		return false;
1217 
1218 	mScriptTranslatorsMap.erase(itFind);
1219 
1220 	return true;
1221 }
1222 
1223 //-----------------------------------------------------------------------------
getNumTranslators() const1224 size_t ShaderGenerator::getNumTranslators() const
1225 {
1226     OGRE_LOCK_AUTO_MUTEX;
1227 
1228 	return mScriptTranslatorsMap.size();
1229 }
1230 
1231 //-----------------------------------------------------------------------------
getTranslator(const AbstractNodePtr & node)1232 ScriptTranslator* ShaderGenerator::getTranslator(const AbstractNodePtr& node)
1233 {
1234     OGRE_LOCK_AUTO_MUTEX;
1235 
1236 	ScriptTranslator *translator = 0;
1237 
1238 	if(node->type == Ogre::ANT_OBJECT)
1239 	{
1240 		ObjectAbstractNode *obj			  = reinterpret_cast<ObjectAbstractNode*>(node.get());
1241 		SGScriptTranslatorIterator itFind = mScriptTranslatorsMap.find(obj->cls);
1242 
1243 		if(itFind != mScriptTranslatorsMap.end())
1244 			translator = itFind->second;
1245 	}
1246 
1247 	return translator;
1248 }
1249 
1250 //-----------------------------------------------------------------------------
serializePassAttributes(MaterialSerializer * ser,SGPass * passEntry)1251 void ShaderGenerator::serializePassAttributes(MaterialSerializer* ser, SGPass* passEntry)
1252 {
1253 
1254 	// Write section header and begin it.
1255 	ser->writeAttribute(3, "rtshader_system");
1256 	ser->beginSection(3);
1257 
1258 	// Grab the custom render state this pass uses.
1259 	RenderState* customRenderState = passEntry->getCustomRenderState();
1260 
1261 	if (customRenderState != NULL)
1262 	{
1263 		// Write each of the sub-render states that composing the final render state.
1264 		const SubRenderStateList& subRenderStates = customRenderState->getTemplateSubRenderStateList();
1265 		SubRenderStateListConstIterator it		= subRenderStates.begin();
1266 		SubRenderStateListConstIterator itEnd	= subRenderStates.end();
1267 
1268 		for (; it != itEnd; ++it)
1269 		{
1270 			SubRenderState* curSubRenderState = *it;
1271 			SubRenderStateFactoryIterator itFactory = mSubRenderStateFactories.find(curSubRenderState->getType());
1272 
1273 			if (itFactory != mSubRenderStateFactories.end())
1274 			{
1275 				SubRenderStateFactory* curFactory = itFactory->second;
1276 				curFactory->writeInstance(ser, curSubRenderState, passEntry->getSrcPass(), passEntry->getDstPass());
1277 			}
1278 		}
1279 	}
1280 
1281 	// Write section end.
1282 	ser->endSection(3);
1283 }
1284 
1285 
1286 
1287 //-----------------------------------------------------------------------------
serializeTextureUnitStateAttributes(MaterialSerializer * ser,SGPass * passEntry,const TextureUnitState * srcTextureUnit)1288 void ShaderGenerator::serializeTextureUnitStateAttributes(MaterialSerializer* ser, SGPass* passEntry, const TextureUnitState* srcTextureUnit)
1289 {
1290 
1291 	// Write section header and begin it.
1292 	ser->writeAttribute(4, "rtshader_system");
1293 	ser->beginSection(4);
1294 
1295 	// Grab the custom render state this pass uses.
1296 	RenderState* customRenderState = passEntry->getCustomRenderState();
1297 
1298 	if (customRenderState != NULL)
1299 	{
1300 		//retrive the destintion texture unit state
1301 		TextureUnitState* dstTextureUnit = NULL;
1302 		unsigned short texIndex = srcTextureUnit->getParent()->getTextureUnitStateIndex(srcTextureUnit);
1303 		if (texIndex < passEntry->getDstPass()->getNumTextureUnitStates())
1304 		{
1305 			dstTextureUnit = passEntry->getDstPass()->getTextureUnitState(texIndex);
1306 		}
1307 
1308 		// Write each of the sub-render states that composing the final render state.
1309 		const SubRenderStateList& subRenderStates = customRenderState->getTemplateSubRenderStateList();
1310 		SubRenderStateListConstIterator it		= subRenderStates.begin();
1311 		SubRenderStateListConstIterator itEnd	= subRenderStates.end();
1312 
1313 		for (; it != itEnd; ++it)
1314 		{
1315 			SubRenderState* curSubRenderState = *it;
1316 			SubRenderStateFactoryIterator itFactory = mSubRenderStateFactories.find(curSubRenderState->getType());
1317 
1318 			if (itFactory != mSubRenderStateFactories.end())
1319 			{
1320 				SubRenderStateFactory* curFactory = itFactory->second;
1321 				curFactory->writeInstance(ser, curSubRenderState, srcTextureUnit, dstTextureUnit);
1322 			}
1323 		}
1324 	}
1325 
1326 	// Write section end.
1327 	ser->endSection(4);
1328 }
1329 
1330 //-----------------------------------------------------------------------------
getVertexShaderCount() const1331 size_t ShaderGenerator::getVertexShaderCount() const
1332 {
1333 	return mProgramManager->getVertexShaderCount();
1334 }
1335 
1336 //-----------------------------------------------------------------------------
getFragmentShaderCount() const1337 size_t ShaderGenerator::getFragmentShaderCount() const
1338 {
1339 	return mProgramManager->getFragmentShaderCount();
1340 }
1341 
1342 //-----------------------------------------------------------------------------
setTargetLanguage(const String & shaderLanguage)1343 void ShaderGenerator::setTargetLanguage(const String& shaderLanguage)
1344 {
1345 	// Make sure that the shader language is supported.
1346 	if (HighLevelGpuProgramManager::getSingleton().isLanguageSupported(shaderLanguage) == false)
1347 	{
1348 		OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1349 			"The language " + shaderLanguage + " is not supported !!",
1350 			"ShaderGenerator::setShaderLanguage");
1351 	}
1352 
1353 	// Case target language changed -> flush the shaders cache.
1354 	if (mShaderLanguage != shaderLanguage)
1355 	{
1356 		mShaderLanguage = shaderLanguage;
1357 		flushShaderCache();
1358 	}
1359 }
1360 
1361 //-----------------------------------------------------------------------------
setShaderCachePath(const String & cachePath)1362 void ShaderGenerator::setShaderCachePath( const String& cachePath )
1363 {
1364 	String stdCachePath = cachePath;
1365 
1366 	// Standardise the cache path in case of none empty string.
1367 	if (stdCachePath.empty() == false)
1368 		stdCachePath = StringUtil::standardisePath(stdCachePath);
1369 
1370 	if (mShaderCachePath != stdCachePath)
1371 	{
1372 		// Remove previous cache path.
1373 		if (mShaderCachePath.empty() == false)
1374 		{
1375 			ResourceGroupManager::getSingleton().removeResourceLocation(mShaderCachePath, GENERATED_SHADERS_GROUP_NAME);
1376 		}
1377 
1378 		mShaderCachePath = stdCachePath;
1379 
1380 		// Case this is a valid file path -> add as resource location in order to make sure that
1381 		// generated shaders could be loaded by the file system archive.
1382 		if (mShaderCachePath.empty() == false)
1383 		{
1384 			// Make sure this is a valid writable path.
1385 			String outTestFileName(mShaderCachePath + "ShaderGenerator.tst");
1386 			std::ofstream outFile(outTestFileName.c_str());
1387 
1388 			if (!outFile)
1389 			{
1390 				OGRE_EXCEPT(Exception::ERR_CANNOT_WRITE_TO_FILE,
1391 					"Could create output files in the given shader cache path '" + mShaderCachePath,
1392 					"ShaderGenerator::setShaderCachePath");
1393 			}
1394 
1395 			// Close and remove the test file.
1396 			outFile.close();
1397 			remove(outTestFileName.c_str());
1398 
1399 			ResourceGroupManager::getSingleton().addResourceLocation(mShaderCachePath, "FileSystem", GENERATED_SHADERS_GROUP_NAME);
1400 		}
1401 	}
1402 }
1403 
1404 //-----------------------------------------------------------------------------
findMaterialEntryIt(const String & materialName,const String & groupName)1405 ShaderGenerator::SGMaterialIterator ShaderGenerator::findMaterialEntryIt(const String& materialName, const String& groupName)
1406 {
1407 	SGMaterialIterator itMatEntry;
1408 	//check if we have auto detect request
1409 	if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
1410 	{
1411 		//find the possible first entry
1412 		itMatEntry = mMaterialEntriesMap.lower_bound(MatGroupPair(materialName,""));
1413 		if ((itMatEntry != mMaterialEntriesMap.end()) &&
1414 			(itMatEntry->first.first != materialName))
1415 		{
1416 			//no entry found
1417 			itMatEntry = mMaterialEntriesMap.end();
1418 		}
1419 	}
1420 	else
1421 	{
1422 		//find entry with group name specified
1423 		itMatEntry = mMaterialEntriesMap.find(MatGroupPair(materialName,groupName));
1424 	}
1425 	return itMatEntry;
1426 }
1427 
1428 //-----------------------------------------------------------------------------
findMaterialEntryIt(const String & materialName,const String & groupName) const1429 ShaderGenerator::SGMaterialConstIterator ShaderGenerator::findMaterialEntryIt(const String& materialName, const String& groupName) const
1430 {
1431 	SGMaterialConstIterator itMatEntry;
1432 	//check if we have auto detect request
1433 	if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
1434 	{
1435 		//find the possible first entry
1436 		itMatEntry = mMaterialEntriesMap.lower_bound(MatGroupPair(materialName,""));
1437 		if ((itMatEntry != mMaterialEntriesMap.end()) &&
1438 			(itMatEntry->first.first != materialName))
1439 		{
1440 			//no entry found
1441 			itMatEntry = mMaterialEntriesMap.end();
1442 		}
1443 	}
1444 	else
1445 	{
1446 		//find entry with group name specified
1447 		itMatEntry = mMaterialEntriesMap.find(MatGroupPair(materialName,groupName));
1448 	}
1449 	return itMatEntry;
1450 }
1451 //-----------------------------------------------------------------------------
getRTShaderSchemeCount() const1452 size_t ShaderGenerator::getRTShaderSchemeCount() const
1453 {
1454     OGRE_LOCK_AUTO_MUTEX;
1455 	return mSchemeEntriesMap.size();
1456 }
1457 //-----------------------------------------------------------------------------
getRTShaderScheme(size_t index) const1458 const String& ShaderGenerator::getRTShaderScheme(size_t index) const
1459 {
1460     OGRE_LOCK_AUTO_MUTEX;
1461 
1462 	SGSchemeMap::const_iterator it = mSchemeEntriesMap.begin();
1463 	while ((index != 0) && (it != mSchemeEntriesMap.end()))
1464 	{
1465 		--index;
1466 		++it;
1467 	}
1468 
1469 	assert((it != mSchemeEntriesMap.end()) && "Index out of bounds");
1470 	if (it != mSchemeEntriesMap.end())
1471 		return it->first;
1472 	else return cBlankString;
1473 }
1474 
1475 //-----------------------------------------------------------------------------
1476 
getIsFinalizing() const1477 bool ShaderGenerator::getIsFinalizing() const
1478 {
1479     return mIsFinalizing;
1480 }
1481 
1482 //-----------------------------------------------------------------------------
SGPass(SGTechnique * parent,Pass * srcPass,Pass * dstPass)1483 ShaderGenerator::SGPass::SGPass(SGTechnique* parent, Pass* srcPass, Pass* dstPass)
1484 {
1485 	mParent				= parent;
1486 	mSrcPass			= srcPass;
1487 	mDstPass			= dstPass;
1488 	mCustomRenderState	= NULL;
1489 	mTargetRenderState	= NULL;
1490 	mDstPass->getUserObjectBindings().setUserAny(SGPass::UserKey, Any(this));
1491 }
1492 
1493 //-----------------------------------------------------------------------------
~SGPass()1494 ShaderGenerator::SGPass::~SGPass()
1495 {
1496 	if (mTargetRenderState != NULL)
1497 	{
1498 		OGRE_DELETE mTargetRenderState;
1499 		mTargetRenderState = NULL;
1500 	}
1501 }
1502 
1503 //-----------------------------------------------------------------------------
buildTargetRenderState()1504 void ShaderGenerator::SGPass::buildTargetRenderState()
1505 {
1506 	const String& schemeName = mParent->getDestinationTechniqueSchemeName();
1507 	const RenderState* renderStateGlobal = ShaderGenerator::getSingleton().getRenderState(schemeName);
1508 
1509 
1510 	mTargetRenderState = OGRE_NEW TargetRenderState;
1511 
1512 	// Set light properties.
1513 	int lightCount[3] = {0};
1514 
1515 	// Use light count definitions of the custom render state if exists.
1516 	if (mCustomRenderState != NULL && mCustomRenderState->getLightCountAutoUpdate() == false)
1517 	{
1518 		mCustomRenderState->getLightCount(lightCount);
1519 	}
1520 
1521 	// Use light count definitions of the global render state if exists.
1522 	else if (renderStateGlobal != NULL)
1523 	{
1524 		renderStateGlobal->getLightCount(lightCount);
1525 	}
1526 
1527 
1528 	mTargetRenderState->setLightCount(lightCount);
1529 
1530 #ifdef RTSHADER_SYSTEM_BUILD_CORE_SHADERS
1531 	// Build the FFP state.
1532 	FFPRenderStateBuilder::getSingleton().buildRenderState(this, mTargetRenderState);
1533 #endif
1534 
1535 
1536 	// Link the target render state with the custom render state of this pass if exists.
1537 	if (mCustomRenderState != NULL)
1538 	{
1539 		mTargetRenderState->link(*mCustomRenderState, mSrcPass, mDstPass);
1540 	}
1541 
1542 	// Link the target render state with the scheme render state of the shader generator.
1543 	if (renderStateGlobal != NULL)
1544 	{
1545 		mTargetRenderState->link(*renderStateGlobal, mSrcPass, mDstPass);
1546 	}
1547 }
1548 
1549 //-----------------------------------------------------------------------------
acquirePrograms()1550 void ShaderGenerator::SGPass::acquirePrograms()
1551 {
1552 	ProgramManager::getSingleton().acquirePrograms(mDstPass, mTargetRenderState);
1553 }
1554 
1555 //-----------------------------------------------------------------------------
releasePrograms()1556 void ShaderGenerator::SGPass::releasePrograms()
1557 {
1558 	ProgramManager::getSingleton().releasePrograms(mDstPass, mTargetRenderState);
1559 }
1560 
1561 //-----------------------------------------------------------------------------
notifyRenderSingleObject(Renderable * rend,const AutoParamDataSource * source,const LightList * pLightList,bool suppressRenderStateChanges)1562 void ShaderGenerator::SGPass::notifyRenderSingleObject(Renderable* rend,  const AutoParamDataSource* source,
1563 											  const LightList* pLightList, bool suppressRenderStateChanges)
1564 {
1565 	if (mTargetRenderState != NULL && suppressRenderStateChanges == false)
1566 		mTargetRenderState->updateGpuProgramsParams(rend, mDstPass, source, pLightList);
1567 }
1568 //-----------------------------------------------------------------------------
getCustomFFPSubState(int subStateOrder)1569 SubRenderState*	ShaderGenerator::SGPass::getCustomFFPSubState(int subStateOrder)
1570 {
1571 	SubRenderState* customSubState = NULL;
1572 
1573 	// Try to override with custom render state of this pass.
1574 	customSubState = getCustomFFPSubState(subStateOrder, mCustomRenderState);
1575 
1576 	// Case no custom sub state of this pass found, try to override with global scheme state.
1577 	if (customSubState == NULL)
1578 	{
1579 		const String& schemeName = mParent->getDestinationTechniqueSchemeName();
1580 		const RenderState* renderStateGlobal = ShaderGenerator::getSingleton().getRenderState(schemeName);
1581 
1582 		customSubState = getCustomFFPSubState(subStateOrder, renderStateGlobal);
1583 	}
1584 
1585 	return customSubState;
1586 }
1587 
1588 //-----------------------------------------------------------------------------
getCustomFFPSubState(int subStateOrder,const RenderState * renderState)1589 SubRenderState*	ShaderGenerator::SGPass::getCustomFFPSubState(int subStateOrder, const RenderState* renderState)
1590 {
1591 	if (renderState != NULL)
1592 	{
1593 		const SubRenderStateList& subRenderStateList = renderState->getTemplateSubRenderStateList();
1594 
1595 		for (SubRenderStateListConstIterator it=subRenderStateList.begin(); it != subRenderStateList.end(); ++it)
1596 		{
1597 			SubRenderState* curSubRenderState = *it;
1598 
1599 			if (curSubRenderState->getExecutionOrder() == subStateOrder)
1600 			{
1601 				SubRenderState* clone;
1602 
1603 				clone = ShaderGenerator::getSingleton().createSubRenderState(curSubRenderState->getType());
1604 				*clone = *curSubRenderState;
1605 
1606 				return clone;
1607 			}
1608 		}
1609 	}
1610 
1611 	return NULL;
1612 }
1613 
1614 //-----------------------------------------------------------------------------
SGTechnique(SGMaterial * parent,Technique * srcTechnique,const String & dstTechniqueSchemeName)1615 ShaderGenerator::SGTechnique::SGTechnique(SGMaterial* parent, Technique* srcTechnique, const String& dstTechniqueSchemeName)
1616 {
1617 	mParent					= parent;
1618 	mSrcTechnique			= srcTechnique;
1619 	mDstTechniqueSchemeName = dstTechniqueSchemeName;
1620 	mDstTechnique			= NULL;
1621 	mBuildDstTechnique		= true;
1622 }
1623 
1624 //-----------------------------------------------------------------------------
createSGPasses()1625 void ShaderGenerator::SGTechnique::createSGPasses()
1626 {
1627 	// Create pass entry for each pass.
1628 	for (unsigned short i=0; i < mSrcTechnique->getNumPasses(); ++i)
1629 	{
1630 		Pass* srcPass = mSrcTechnique->getPass(i);
1631 		Pass* dstPass = mDstTechnique->getPass(i);
1632 
1633 		SGPass* passEntry = OGRE_NEW SGPass(this, srcPass, dstPass);
1634 
1635 		if (i < mCustomRenderStates.size())
1636 			passEntry->setCustomRenderState(mCustomRenderStates[i]);
1637 		mPassEntries.push_back(passEntry);
1638 	}
1639 }
1640 
1641 //-----------------------------------------------------------------------------
~SGTechnique()1642 ShaderGenerator::SGTechnique::~SGTechnique()
1643 {
1644 	const String& materialName = mParent->getMaterialName();
1645 	const String& groupName = mParent->getGroupName();
1646 
1647 	if (MaterialManager::getSingleton().resourceExists(materialName))
1648 	{
1649 		MaterialPtr mat = MaterialManager::getSingleton().getByName(materialName, groupName);
1650 
1651 		// Remove the destination technique from parent material.
1652 		for (unsigned int i=0; i < mat->getNumTechniques(); ++i)
1653 		{
1654 			if (mDstTechnique == mat->getTechnique(i))
1655 			{
1656 				// Unload the generated technique in order tor free referenced resources.
1657 				mDstTechnique->_unload();
1658 
1659 				// Remove the generated technique in order to restore the material to its original state.
1660 				mat->removeTechnique(i);
1661 
1662                 // touch when finalizing - will reload the textures - so no touch if finalizing
1663                 if (ShaderGenerator::getSingleton().getIsFinalizing() == false)
1664                 {
1665                     // Make sure the material goes back to its original state.
1666                     mat->touch();
1667                 }
1668 				break;
1669 			}
1670 		}
1671 	}
1672 
1673 	// Release CPU/GPU programs that associated with this technique passes.
1674 	for (SGPassIterator itPass = mPassEntries.begin(); itPass != mPassEntries.end(); ++itPass)
1675 	{
1676 		(*itPass)->releasePrograms();
1677 	}
1678 
1679 	// Destroy the passes.
1680 	destroySGPasses();
1681 
1682 	// Delete the custom render states of each pass if exist.
1683 	for (unsigned int i=0; i < mCustomRenderStates.size(); ++i)
1684 	{
1685 		if (mCustomRenderStates[i] != NULL)
1686 		{
1687 			OGRE_DELETE mCustomRenderStates[i];
1688 			mCustomRenderStates[i] = NULL;
1689 		}
1690 	}
1691 	mCustomRenderStates.clear();
1692 
1693 }
1694 
1695 //-----------------------------------------------------------------------------
destroySGPasses()1696 void ShaderGenerator::SGTechnique::destroySGPasses()
1697 {
1698 	for (SGPassIterator itPass = mPassEntries.begin(); itPass != mPassEntries.end(); ++itPass)
1699 	{
1700 		OGRE_DELETE (*itPass);
1701 	}
1702 	mPassEntries.clear();
1703 }
1704 
1705 //-----------------------------------------------------------------------------
buildTargetRenderState()1706 void ShaderGenerator::SGTechnique::buildTargetRenderState()
1707 {
1708 	// Remove existing destination technique and passes
1709 	// in order to build it again from scratch.
1710 	if (mDstTechnique != NULL)
1711 	{
1712 		Material* mat = mSrcTechnique->getParent();
1713 
1714 		for (unsigned short i=0; i < mat->getNumTechniques(); ++i)
1715 		{
1716 			if (mat->getTechnique(i) == mDstTechnique)
1717 			{
1718 				mat->removeTechnique(i);
1719 				break;
1720 			}
1721 		}
1722 		destroySGPasses();
1723 	}
1724 
1725 	// Create the destination technique and passes.
1726 	mDstTechnique	= mSrcTechnique->getParent()->createTechnique();
1727 	mDstTechnique->getUserObjectBindings().setUserAny(SGTechnique::UserKey, Any(this));
1728 	*mDstTechnique	= *mSrcTechnique;
1729 	mDstTechnique->setSchemeName(mDstTechniqueSchemeName);
1730 	createSGPasses();
1731 
1732 
1733 	// Build render state for each pass.
1734 	for (SGPassIterator itPass = mPassEntries.begin(); itPass != mPassEntries.end(); ++itPass)
1735 	{
1736 		(*itPass)->buildTargetRenderState();
1737 	}
1738 }
1739 
1740 //-----------------------------------------------------------------------------
acquirePrograms()1741 void ShaderGenerator::SGTechnique::acquirePrograms()
1742 {
1743 	for (SGPassIterator itPass = mPassEntries.begin(); itPass != mPassEntries.end(); ++itPass)
1744 	{
1745 		(*itPass)->acquirePrograms();
1746 	}
1747 }
1748 
1749 //-----------------------------------------------------------------------------
releasePrograms()1750 void ShaderGenerator::SGTechnique::releasePrograms()
1751 {
1752 	// Remove destination technique.
1753 	if (mDstTechnique != NULL)
1754 	{
1755 		Material* mat = mSrcTechnique->getParent();
1756 
1757 		for (unsigned short i=0; i < mat->getNumTechniques(); ++i)
1758 		{
1759 			if (mat->getTechnique(i) == mDstTechnique)
1760 			{
1761 				mat->removeTechnique(i);
1762 				break;
1763 			}
1764 		}
1765 		mDstTechnique = NULL;
1766 	}
1767 
1768 	// Release CPU/GPU programs that associated with this technique passes.
1769 	for (SGPassIterator itPass = mPassEntries.begin(); itPass != mPassEntries.end(); ++itPass)
1770 	{
1771 		(*itPass)->releasePrograms();
1772 	}
1773 
1774 	// Destroy the passes.
1775 	destroySGPasses();
1776 }
1777 
1778 //-----------------------------------------------------------------------------
getRenderState(unsigned short passIndex)1779 RenderState* ShaderGenerator::SGTechnique::getRenderState(unsigned short passIndex)
1780 {
1781 	RenderState* renderState = NULL;
1782 
1783 	if (passIndex >= mCustomRenderStates.size())
1784 		mCustomRenderStates.resize(passIndex + 1, NULL);
1785 
1786 	renderState = mCustomRenderStates[passIndex];
1787 	if (renderState == NULL)
1788 	{
1789 		renderState = OGRE_NEW RenderState;
1790 		mCustomRenderStates[passIndex] = renderState;
1791 	}
1792 
1793 	return renderState;
1794 }
1795 //-----------------------------------------------------------------------------
hasRenderState(unsigned short passIndex)1796 bool ShaderGenerator::SGTechnique::hasRenderState(unsigned short passIndex)
1797 {
1798 	return (passIndex < mCustomRenderStates.size()) && (mCustomRenderStates[passIndex] != NULL);
1799 }
1800 
1801 
1802 //-----------------------------------------------------------------------------
SGScheme(const String & schemeName)1803 ShaderGenerator::SGScheme::SGScheme(const String& schemeName)
1804 {
1805 	mOutOfDate	 = true;
1806 	mRenderState = NULL;
1807 	mName		 = schemeName;
1808 	mFogMode	 = FOG_NONE;
1809 }
1810 
1811 //-----------------------------------------------------------------------------
~SGScheme()1812 ShaderGenerator::SGScheme::~SGScheme()
1813 {
1814 	if (mRenderState != NULL)
1815 	{
1816 		OGRE_DELETE mRenderState;
1817 		mRenderState = NULL;
1818 	}
1819 }
1820 
1821 //-----------------------------------------------------------------------------
getRenderState()1822 RenderState* ShaderGenerator::SGScheme::getRenderState()
1823 {
1824 	if (mRenderState == NULL)
1825 		mRenderState = OGRE_NEW RenderState;
1826 
1827 	return mRenderState;
1828 }
1829 
1830 //-----------------------------------------------------------------------------
getRenderState(const String & materialName,const String & groupName,unsigned short passIndex)1831 RenderState* ShaderGenerator::SGScheme::getRenderState(const String& materialName, const String& groupName, unsigned short passIndex)
1832 {
1833 	SGTechniqueIterator itTech;
1834 
1835 	// Find the desired technique.
1836 	bool doAutoDetect = groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;
1837 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1838 	{
1839 		SGTechnique* curTechEntry = *itTech;
1840 		Material* curMat = curTechEntry->getSourceTechnique()->getParent();
1841 		if ((curMat->getName() == materialName) &&
1842 			((doAutoDetect == true) || (curMat->getGroup() == groupName)))
1843 		{
1844 			return curTechEntry->getRenderState(passIndex);
1845 		}
1846 	}
1847 
1848 	return NULL;
1849 }
1850 
1851 
1852 //-----------------------------------------------------------------------------
addTechniqueEntry(SGTechnique * techEntry)1853 void ShaderGenerator::SGScheme::addTechniqueEntry(SGTechnique* techEntry)
1854 {
1855 	mTechniqueEntries.push_back(techEntry);
1856 
1857 	// Mark as out of data.
1858 	mOutOfDate = true;
1859 }
1860 
1861 //-----------------------------------------------------------------------------
removeTechniqueEntry(SGTechnique * techEntry)1862 void ShaderGenerator::SGScheme::removeTechniqueEntry(SGTechnique* techEntry)
1863 {
1864 	SGTechniqueIterator itTech;
1865 
1866 	// Build render state for each technique.
1867 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1868 	{
1869 		SGTechnique* curTechEntry = *itTech;
1870 
1871 		if (curTechEntry == techEntry)
1872 		{
1873 			mTechniqueEntries.erase(itTech);
1874 			break;
1875 		}
1876 	}
1877 }
1878 
1879 //-----------------------------------------------------------------------------
validate()1880 void ShaderGenerator::SGScheme::validate()
1881 {
1882 	// Synchronize with light settings.
1883 	synchronizeWithLightSettings();
1884 
1885 	// Synchronize with fog settings.
1886 	synchronizeWithFogSettings();
1887 
1888 	// The target scheme is up to date.
1889 	if (mOutOfDate == false)
1890 		return;
1891 
1892 	SGTechniqueIterator itTech;
1893 
1894 	// Build render state for each technique.
1895 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1896 	{
1897 		SGTechnique* curTechEntry = *itTech;
1898 
1899 		if (curTechEntry->getBuildDestinationTechnique())
1900 			curTechEntry->buildTargetRenderState();
1901 	}
1902 
1903 	// Acquire GPU programs for each technique.
1904 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1905 	{
1906 		SGTechnique* curTechEntry = *itTech;
1907 
1908 		if (curTechEntry->getBuildDestinationTechnique())
1909 			curTechEntry->acquirePrograms();
1910 	}
1911 
1912 	// Turn off the build destination technique flag.
1913 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1914 	{
1915 		SGTechnique* curTechEntry = *itTech;
1916 
1917 		curTechEntry->setBuildDestinationTechnique(false);
1918 	}
1919 
1920 	// Mark this scheme as up to date.
1921 	mOutOfDate = false;
1922 }
1923 
1924 //-----------------------------------------------------------------------------
synchronizeWithLightSettings()1925 void ShaderGenerator::SGScheme::synchronizeWithLightSettings()
1926 {
1927 	SceneManager* sceneManager = ShaderGenerator::getSingleton().getActiveSceneManager();
1928 	RenderState* curRenderState = getRenderState();
1929 
1930 	if (sceneManager != NULL && curRenderState->getLightCountAutoUpdate())
1931 	{
1932 		const LightList& lightList =  sceneManager->_getLightsAffectingFrustum();
1933 
1934 		int sceneLightCount[3] = {0};
1935 		int currLightCount[3] = {0};
1936 
1937 		for (unsigned int i=0; i < lightList.size(); ++i)
1938 		{
1939 			sceneLightCount[lightList[i]->getType()]++;
1940 		}
1941 
1942 		mRenderState->getLightCount(currLightCount);
1943 
1944 		// Case light state has been changed -> invalidate this scheme.
1945 		if (currLightCount[0] != sceneLightCount[0] ||
1946 			currLightCount[1] != sceneLightCount[1] ||
1947 			currLightCount[2] != sceneLightCount[2])
1948 		{
1949 			curRenderState->setLightCount(sceneLightCount);
1950 			invalidate();
1951 		}
1952 	}
1953 }
1954 
1955 //-----------------------------------------------------------------------------
synchronizeWithFogSettings()1956 void ShaderGenerator::SGScheme::synchronizeWithFogSettings()
1957 {
1958 	SceneManager* sceneManager = ShaderGenerator::getSingleton().getActiveSceneManager();
1959 
1960 	if (sceneManager != NULL && sceneManager->getFogMode() != mFogMode)
1961 	{
1962 		mFogMode = sceneManager->getFogMode();
1963 		invalidate();
1964 	}
1965 }
1966 
1967 //-----------------------------------------------------------------------------
validate(const String & materialName,const String & groupName)1968 bool ShaderGenerator::SGScheme::validate(const String& materialName, const String& groupName)
1969 {
1970 	// Synchronize with light settings.
1971 	synchronizeWithLightSettings();
1972 
1973 	// Synchronize with fog settings.
1974 	synchronizeWithFogSettings();
1975 
1976 
1977 	SGTechniqueIterator itTech;
1978 
1979 	// Find the desired technique.
1980 	bool doAutoDetect = groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;
1981 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
1982 	{
1983 		SGTechnique* curTechEntry = *itTech;
1984 		const SGMaterial* curMat = curTechEntry->getParent();
1985 		if ((curMat->getMaterialName() == materialName) &&
1986 			((doAutoDetect == true) || (curMat->getGroupName() == groupName)) &&
1987 			(curTechEntry->getBuildDestinationTechnique()))
1988 		{
1989 			// Build render state for each technique.
1990 			curTechEntry->buildTargetRenderState();
1991 
1992 			// Acquire the CPU/GPU programs.
1993 			curTechEntry->acquirePrograms();
1994 
1995 			// Turn off the build destination technique flag.
1996 			curTechEntry->setBuildDestinationTechnique(false);
1997 
1998 			return true;
1999 		}
2000 	}
2001 
2002 	return false;
2003 }
2004 //-----------------------------------------------------------------------------
invalidate(const String & materialName,const String & groupName)2005 void ShaderGenerator::SGScheme::invalidate(const String& materialName, const String& groupName)
2006 {
2007 	SGTechniqueIterator itTech;
2008 
2009 	// Find the desired technique.
2010 	bool doAutoDetect = groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME;
2011 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
2012 	{
2013 		SGTechnique* curTechEntry = *itTech;
2014 		const SGMaterial* curMaterial = curTechEntry->getParent();
2015 		if ((curMaterial->getMaterialName() == materialName) &&
2016 			((doAutoDetect == true) || (curMaterial->getGroupName() == groupName)))
2017 		{
2018 			// Turn on the build destination technique flag.
2019 			curTechEntry->setBuildDestinationTechnique(true);
2020 			break;
2021 		}
2022 	}
2023 
2024 	mOutOfDate = true;
2025 }
2026 
2027 //-----------------------------------------------------------------------------
invalidate()2028 void ShaderGenerator::SGScheme::invalidate()
2029 {
2030 	SGTechniqueIterator itTech;
2031 
2032 	// Turn on the build destination technique flag of all techniques.
2033 	for (itTech = mTechniqueEntries.begin(); itTech != mTechniqueEntries.end(); ++itTech)
2034 	{
2035 		SGTechnique* curTechEntry = *itTech;
2036 
2037 		curTechEntry->setBuildDestinationTechnique(true);
2038 	}
2039 
2040 	mOutOfDate = true;
2041 }
2042 
2043 }
2044 }
2045