1 #include "pch.h"
2 #include "Factory.hpp"
3 
4 #include <stdexcept>
5 #include <iostream>
6 
7 #include <boost/algorithm/string.hpp>
8 #include <boost/filesystem.hpp>
9 #include <boost/lexical_cast.hpp>
10 
11 #include "Platform.hpp"
12 #include "ScriptLoader.hpp"
13 #include "ShaderSet.hpp"
14 #include "MaterialInstanceTextureUnit.hpp"
15 
16 namespace sh
17 {
18 	Factory* Factory::sThis = 0;
19 	const std::string Factory::mBinaryCacheName = "binaryCache";
20 
getInstance()21 	Factory& Factory::getInstance()
22 	{
23 		assert (sThis);
24 		return *sThis;
25 	}
26 
getInstancePtr()27 	Factory* Factory::getInstancePtr()
28 	{
29 		return sThis;
30 	}
31 
Factory(Platform * platform)32 	Factory::Factory (Platform* platform)
33 		: mPlatform(platform)
34 		, mShadersEnabled(true)
35 		, mShaderDebugOutputEnabled(false)
36 		, mCurrentLanguage(Language_None)
37 		, mListener(NULL)
38 		, mCurrentConfiguration(NULL)
39 		, mCurrentLodConfiguration(NULL)
40 		, mReadMicrocodeCache(false)
41 		, mWriteMicrocodeCache(false)
42 		, mReadSourceCache(false)
43 		, mWriteSourceCache(false)
44 	{
45 		assert (!sThis);
46 		sThis = this;
47 
48 		mPlatform->setFactory(this);
49 	}
50 
loadAllFiles()51 	void Factory::loadAllFiles()
52 	{
53 		assert(mCurrentLanguage != Language_None);
54 
55 		try
56 		{
57 			if (boost::filesystem::exists (mPlatform->getCacheFolder () + "/lastModified.txt"))
58 			{
59 				std::ifstream file;
60 				file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str());
61 
62 				std::string line;
63 				while (getline(file, line))
64 				{
65 					std::string sourceFile = line;
66 
67 					if (!getline(file, line))
68 						assert(0);
69 
70 					int modified = boost::lexical_cast<int>(line);
71 
72 					mShadersLastModified[sourceFile] = modified;
73 				}
74 			}
75 		}
76 		catch (std::exception& e)
77 		{
78 			std::cerr << "Failed to load shader modification index: " << e.what() << std::endl;
79 			mShadersLastModified.clear();
80 		}
81 
82 		// load configurations
83 		{
84 			ScriptLoader shaderSetLoader(".configuration");
85 			ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
86 			std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
87 			for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
88 				it != nodes.end(); ++it)
89 			{
90 				if (!(it->second->getName() == "configuration"))
91 				{
92 					std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .configuration" << std::endl;
93 					break;
94 				}
95 
96 				Configuration newConfiguration;
97 				newConfiguration.setParent(&mGlobalSettings);
98 				newConfiguration.setSourceFile (it->second->mFileName);
99 
100 				std::vector<ScriptNode*> props = it->second->getChildren();
101 				for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
102 				{
103 					std::string name = (*propIt)->getName();
104 					std::string val = (*propIt)->getValue();
105 
106 					newConfiguration.setProperty (name, makeProperty(val));
107 				}
108 
109 				mConfigurations[it->first] = newConfiguration;
110 			}
111 		}
112 
113 		// load lod configurations
114 		{
115 			ScriptLoader lodLoader(".lod");
116 			ScriptLoader::loadAllFiles (&lodLoader, mPlatform->getBasePath());
117 			std::map <std::string, ScriptNode*> nodes = lodLoader.getAllConfigScripts();
118 			for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
119 				it != nodes.end(); ++it)
120 			{
121 				if (!(it->second->getName() == "lod_configuration"))
122 				{
123 					std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .lod" << std::endl;
124 					break;
125 				}
126 
127 				if (it->first == "0")
128 				{
129 					throw std::runtime_error("lod level 0 (max lod) can't have a configuration");
130 				}
131 
132 				PropertySetGet newLod;
133 
134 				std::vector<ScriptNode*> props = it->second->getChildren();
135 				for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
136 				{
137 					std::string name = (*propIt)->getName();
138 					std::string val = (*propIt)->getValue();
139 
140 					newLod.setProperty (name, makeProperty(val));
141 				}
142 
143 				mLodConfigurations[boost::lexical_cast<int>(it->first)] = newLod;
144 			}
145 		}
146 
147 		// load shader sets
148 		bool removeBinaryCache = reloadShaders();
149 
150 		// load materials
151 		{
152 			ScriptLoader materialLoader(".mat");
153 			ScriptLoader::loadAllFiles (&materialLoader, mPlatform->getBasePath());
154 
155 			std::map <std::string, ScriptNode*> nodes = materialLoader.getAllConfigScripts();
156 			for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
157 				it != nodes.end(); ++it)
158 			{
159 				if (!(it->second->getName() == "material"))
160 				{
161 					std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .mat" << std::endl;
162 					break;
163 				}
164 
165 				MaterialInstance newInstance(it->first, this);
166 				newInstance.create(mPlatform);
167 				if (!mShadersEnabled)
168 					newInstance.setShadersEnabled (false);
169 
170 				newInstance.setSourceFile (it->second->mFileName);
171 
172 				std::vector<ScriptNode*> props = it->second->getChildren();
173 				for (std::vector<ScriptNode*>::const_iterator propIt = props.begin(); propIt != props.end(); ++propIt)
174 				{
175 					std::string name = (*propIt)->getName();
176 
177 					std::string val = (*propIt)->getValue();
178 
179 					if (name == "pass")
180 					{
181 						MaterialInstancePass* newPass = newInstance.createPass();
182 						std::vector<ScriptNode*> props2 = (*propIt)->getChildren();
183 						for (std::vector<ScriptNode*>::const_iterator propIt2 = props2.begin(); propIt2 != props2.end(); ++propIt2)
184 						{
185 							std::string name2 = (*propIt2)->getName();
186 							std::string val2 = (*propIt2)->getValue();
187 
188 							if (name2 == "shader_properties")
189 							{
190 								std::vector<ScriptNode*> shaderProps = (*propIt2)->getChildren();
191 								for (std::vector<ScriptNode*>::const_iterator shaderPropIt = shaderProps.begin(); shaderPropIt != shaderProps.end(); ++shaderPropIt)
192 								{
193 									std::string val = (*shaderPropIt)->getValue();
194 									newPass->mShaderProperties.setProperty((*shaderPropIt)->getName(), makeProperty(val));
195 								}
196 							}
197 							else if (name2 == "texture_unit")
198 							{
199 								MaterialInstanceTextureUnit* newTex = newPass->createTextureUnit(val2);
200 								std::vector<ScriptNode*> texProps = (*propIt2)->getChildren();
201 								for (std::vector<ScriptNode*>::const_iterator texPropIt = texProps.begin(); texPropIt != texProps.end(); ++texPropIt)
202 								{
203 									std::string val = (*texPropIt)->getValue();
204 									newTex->setProperty((*texPropIt)->getName(), makeProperty(val));
205 								}
206 							}
207 							else
208 								newPass->setProperty((*propIt2)->getName(), makeProperty(val2));
209 						}
210 					}
211 					else if (name == "parent")
212 						newInstance.setParentInstance(val);
213 					else
214 						newInstance.setProperty((*propIt)->getName(), makeProperty(val));
215 				}
216 
217 				if (newInstance.hasProperty("create_configuration"))
218 				{
219 					std::string config = retrieveValue<StringValue>(newInstance.getProperty("create_configuration"), NULL).get();
220 					newInstance.createForConfiguration (config, 0);
221 				}
222 
223 				mMaterials.insert (std::make_pair(it->first, newInstance));
224 			}
225 
226 			// now that all materials are loaded, replace the parent names with the actual pointers to parent
227 			for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
228 			{
229 				std::string parent = it->second.getParentInstance();
230 				if (parent != "")
231 				{
232 					if (mMaterials.find (it->second.getParentInstance()) == mMaterials.end())
233 						throw std::runtime_error ("Unable to find parent for material instance \"" + it->first + "\"");
234 					it->second.setParent(&mMaterials.find(parent)->second);
235 				}
236 			}
237 		}
238 
239 		if (mPlatform->supportsShaderSerialization () && mReadMicrocodeCache && !removeBinaryCache)
240 		{
241 			std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
242 			if (boost::filesystem::exists(file))
243 			{
244 				mPlatform->deserializeShaders (file);
245 			}
246 		}
247 	}
248 
~Factory()249 	Factory::~Factory ()
250 	{
251 		mShaderSets.clear();
252 
253 		if (mPlatform->supportsShaderSerialization () && mWriteMicrocodeCache)
254 		{
255 			std::string file = mPlatform->getCacheFolder () + "/" + mBinaryCacheName;
256 			mPlatform->serializeShaders (file);
257 		}
258 
259 		if (mReadSourceCache)
260 		{
261 			// save the last modified time of shader sources (as of when they were loaded)
262 			std::ofstream file;
263 			file.open(std::string(mPlatform->getCacheFolder () + "/lastModified.txt").c_str());
264 
265 			for (LastModifiedMap::const_iterator it = mShadersLastModifiedNew.begin(); it != mShadersLastModifiedNew.end(); ++it)
266 			{
267 				file << it->first << "\n" << it->second << std::endl;
268 			}
269 
270 			file.close();
271 		}
272 
273 		delete mPlatform;
274 		sThis = 0;
275 	}
276 
searchInstance(const std::string & name)277 	MaterialInstance* Factory::searchInstance (const std::string& name)
278 	{
279 		MaterialMap::iterator it = mMaterials.find(name);
280 		if (it != mMaterials.end())
281 			return &(it->second);
282 		else
283 			return NULL;
284 	}
285 
findInstance(const std::string & name)286 	MaterialInstance* Factory::findInstance (const std::string& name)
287 	{
288 		MaterialInstance* m = searchInstance(name);
289 		assert (m);
290 		return m;
291 	}
292 
requestMaterial(const std::string & name,const std::string & configuration,unsigned short lodIndex)293 	MaterialInstance* Factory::requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex)
294 	{
295 		MaterialInstance* m = searchInstance (name);
296 
297 		if (configuration != "Default" && mConfigurations.find(configuration) == mConfigurations.end())
298 			return NULL;
299 
300 		if (m)
301 		{
302 			if (m->createForConfiguration (configuration, 0))
303 			{
304 				if (mListener)
305 					mListener->materialCreated (m, configuration, 0);
306 			}
307 			else
308 				return NULL;
309 
310 			for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it)
311 			{
312 				if (m->createForConfiguration (configuration, it->first))
313 				{
314 					if (mListener)
315 						mListener->materialCreated (m, configuration, it->first);
316 				}
317 				else
318 					return NULL;
319 			}
320 		}
321 		return m;
322 	}
323 
createMaterialInstance(const std::string & name,const std::string & parentInstance)324 	MaterialInstance* Factory::createMaterialInstance (const std::string& name, const std::string& parentInstance)
325 	{
326 		if (parentInstance != "" && mMaterials.find(parentInstance) == mMaterials.end())
327 			throw std::runtime_error ("trying to clone material that does not exist");
328 
329 		MaterialInstance newInstance(name, this);
330 
331 		if (!mShadersEnabled)
332 			newInstance.setShadersEnabled(false);
333 
334 		if (parentInstance != "")
335 			newInstance.setParent (&mMaterials.find(parentInstance)->second);
336 
337 		newInstance.create(mPlatform);
338 
339 		mMaterials.insert (std::make_pair(name, newInstance));
340 
341 		return &mMaterials.find(name)->second;
342 	}
343 
destroyMaterialInstance(const std::string & name)344 	void Factory::destroyMaterialInstance (const std::string& name)
345 	{
346 		if (mMaterials.find(name) != mMaterials.end())
347 			mMaterials.erase(name);
348 	}
349 
setShadersEnabled(bool enabled)350 	void Factory::setShadersEnabled (bool enabled)
351 	{
352 		mShadersEnabled = enabled;
353 		for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
354 		{
355 			it->second.setShadersEnabled(enabled);
356 		}
357 	}
358 
setGlobalSetting(const std::string & name,const std::string & value)359 	void Factory::setGlobalSetting (const std::string& name, const std::string& value)
360 	{
361 		bool changed = true;
362 		if (mGlobalSettings.hasProperty(name))
363 			changed = (retrieveValue<StringValue>(mGlobalSettings.getProperty(name), NULL).get() != value);
364 
365 		mGlobalSettings.setProperty (name, makeProperty<StringValue>(new StringValue(value)));
366 
367 		if (changed)
368 		{
369 			for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
370 			{
371 				it->second.destroyAll();
372 			}
373 		}
374 	}
375 
setSharedParameter(const std::string & name,PropertyValuePtr value)376 	void Factory::setSharedParameter (const std::string& name, PropertyValuePtr value)
377 	{
378 		mPlatform->setSharedParameter(name, value);
379 	}
380 
getShaderSet(const std::string & name)381 	ShaderSet* Factory::getShaderSet (const std::string& name)
382 	{
383 		if (mShaderSets.find(name) == mShaderSets.end())
384 		{
385 			std::stringstream msg;
386 			msg << "Shader '" << name << "' not found";
387 			throw std::runtime_error(msg.str());
388 		}
389 		return &mShaderSets.find(name)->second;
390 	}
391 
getPlatform()392 	Platform* Factory::getPlatform ()
393 	{
394 		return mPlatform;
395 	}
396 
getCurrentLanguage()397 	Language Factory::getCurrentLanguage ()
398 	{
399 		return mCurrentLanguage;
400 	}
401 
setCurrentLanguage(Language lang)402 	void Factory::setCurrentLanguage (Language lang)
403 	{
404 		bool changed = (mCurrentLanguage != lang);
405 		mCurrentLanguage = lang;
406 
407 		if (changed)
408 		{
409 			for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
410 			{
411 				it->second.destroyAll();
412 			}
413 		}
414 	}
415 
notifyConfigurationChanged()416 	void Factory::notifyConfigurationChanged()
417 	{
418 		for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
419 		{
420 			it->second.destroyAll();
421 		}
422 	}
423 
getMaterialInstance(const std::string & name)424 	MaterialInstance* Factory::getMaterialInstance (const std::string& name)
425 	{
426 		return findInstance(name);
427 	}
428 
setTextureAlias(const std::string & alias,const std::string & realName)429 	void Factory::setTextureAlias (const std::string& alias, const std::string& realName)
430 	{
431 		mTextureAliases[alias] = realName;
432 
433 		// update the already existing texture units
434 		for (std::map<TextureUnitState*, std::string>::iterator it = mTextureAliasInstances.begin(); it != mTextureAliasInstances.end(); ++it)
435 		{
436 			if (it->second == alias)
437 			{
438 				it->first->setTextureName(realName);
439 			}
440 		}
441 	}
442 
retrieveTextureAlias(const std::string & name)443 	std::string Factory::retrieveTextureAlias (const std::string& name)
444 	{
445 		TextureAliasMap::iterator it = mTextureAliases.find(name);
446 		if (it != mTextureAliases.end())
447 			return it->second;
448 		else
449 			return "";
450 	}
451 
getConfiguration(const std::string & name)452 	Configuration* Factory::getConfiguration (const std::string& name)
453 	{
454 		return &mConfigurations[name];
455 	}
456 
createConfiguration(const std::string & name)457 	void Factory::createConfiguration (const std::string& name)
458 	{
459 		mConfigurations[name].setParent (&mGlobalSettings);
460 	}
461 
destroyConfiguration(const std::string & name)462 	void Factory::destroyConfiguration(const std::string &name)
463 	{
464 		mConfigurations.erase(name);
465 	}
466 
registerLodConfiguration(int index,PropertySetGet configuration)467 	void Factory::registerLodConfiguration (int index, PropertySetGet configuration)
468 	{
469 		mLodConfigurations[index] = configuration;
470 	}
471 
setMaterialListener(MaterialListener * listener)472 	void Factory::setMaterialListener (MaterialListener* listener)
473 	{
474 		mListener = listener;
475 	}
476 
addTextureAliasInstance(const std::string & name,TextureUnitState * t)477 	void Factory::addTextureAliasInstance (const std::string& name, TextureUnitState* t)
478 	{
479 		mTextureAliasInstances[t] = name;
480 	}
481 
removeTextureAliasInstances(TextureUnitState * t)482 	void Factory::removeTextureAliasInstances (TextureUnitState* t)
483 	{
484 		mTextureAliasInstances.erase(t);
485 	}
486 
setActiveConfiguration(const std::string & configuration)487 	void Factory::setActiveConfiguration (const std::string& configuration)
488 	{
489 		if (configuration == "Default")
490 			mCurrentConfiguration = 0;
491 		else
492 		{
493 			assert (mConfigurations.find(configuration) != mConfigurations.end());
494 			mCurrentConfiguration = &mConfigurations[configuration];
495 		}
496 	}
497 
setActiveLodLevel(int level)498 	void Factory::setActiveLodLevel (int level)
499 	{
500 		if (level == 0)
501 			mCurrentLodConfiguration = 0;
502 		else
503 		{
504 			assert (mLodConfigurations.find(level) != mLodConfigurations.end());
505 			mCurrentLodConfiguration = &mLodConfigurations[level];
506 		}
507 	}
508 
setShaderDebugOutputEnabled(bool enabled)509 	void Factory::setShaderDebugOutputEnabled (bool enabled)
510 	{
511 		mShaderDebugOutputEnabled = enabled;
512 	}
513 
getCurrentGlobalSettings()514 	PropertySetGet* Factory::getCurrentGlobalSettings()
515 	{
516 		PropertySetGet* p = &mGlobalSettings;
517 
518 		// current global settings are affected by active configuration & active lod configuration
519 
520 		if (mCurrentConfiguration)
521 		{
522 			p = mCurrentConfiguration;
523 		}
524 
525 		if (mCurrentLodConfiguration)
526 		{
527 			mCurrentLodConfiguration->setParent(p);
528 			p = mCurrentLodConfiguration;
529 		}
530 
531 		return p;
532 	}
533 
saveAll()534 	void Factory::saveAll ()
535 	{
536 		std::map<std::string, std::ofstream*> files;
537 		for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
538 		{
539 			if (it->second.getSourceFile().empty())
540 				continue;
541 			if (files.find(it->second.getSourceFile()) == files.end())
542 			{
543 				/// \todo check if this is actually the same file, since there can be different paths to the same file
544 				std::ofstream* stream = new std::ofstream();
545 				stream->open (it->second.getSourceFile().c_str());
546 
547 				files[it->second.getSourceFile()] = stream;
548 			}
549 			it->second.save (*files[it->second.getSourceFile()]);
550 		}
551 
552 		for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
553 		{
554 			delete it->second;
555 		}
556 		files.clear();
557 
558 		for (ConfigurationMap::iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
559 		{
560 			if (it->second.getSourceFile().empty())
561 				continue;
562 			if (files.find(it->second.getSourceFile()) == files.end())
563 			{
564 				/// \todo check if this is actually the same file, since there can be different paths to the same file
565 				std::ofstream* stream = new std::ofstream();
566 				stream->open (it->second.getSourceFile().c_str());
567 
568 				files[it->second.getSourceFile()] = stream;
569 			}
570 			it->second.save (it->first, *files[it->second.getSourceFile()]);
571 		}
572 
573 		for (std::map<std::string, std::ofstream*>::iterator it = files.begin(); it != files.end(); ++it)
574 		{
575 			delete it->second;
576 		}
577 	}
578 
listMaterials(std::vector<std::string> & out)579 	void Factory::listMaterials(std::vector<std::string> &out)
580 	{
581 		for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
582 		{
583 			out.push_back(it->first);
584 		}
585 	}
586 
listGlobalSettings(std::map<std::string,std::string> & out)587 	void Factory::listGlobalSettings(std::map<std::string, std::string> &out)
588 	{
589 		const PropertyMap& properties = mGlobalSettings.listProperties();
590 
591 		for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
592 		{
593 			out[it->first] = retrieveValue<StringValue>(mGlobalSettings.getProperty(it->first), NULL).get();
594 		}
595 	}
596 
listConfigurationSettings(const std::string & name,std::map<std::string,std::string> & out)597 	void Factory::listConfigurationSettings(const std::string& name, std::map<std::string, std::string> &out)
598 	{
599 		const PropertyMap& properties = mConfigurations[name].listProperties();
600 
601 		for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it)
602 		{
603 			out[it->first] = retrieveValue<StringValue>(mConfigurations[name].getProperty(it->first), NULL).get();
604 		}
605 	}
606 
listConfigurationNames(std::vector<std::string> & out)607 	void Factory::listConfigurationNames(std::vector<std::string> &out)
608 	{
609 		for (ConfigurationMap::const_iterator it = mConfigurations.begin(); it != mConfigurations.end(); ++it)
610 		{
611 			out.push_back(it->first);
612 		}
613 	}
614 
listShaderSets(std::vector<std::string> & out)615 	void Factory::listShaderSets(std::vector<std::string> &out)
616 	{
617 		for (ShaderSetMap::const_iterator it = mShaderSets.begin(); it != mShaderSets.end(); ++it)
618 		{
619 			out.push_back(it->first);
620 		}
621 	}
622 
_ensureMaterial(const std::string & name,const std::string & configuration)623 	void Factory::_ensureMaterial(const std::string& name, const std::string& configuration)
624 	{
625 		MaterialInstance* m = searchInstance (name);
626 		assert(m);
627 
628 		m->createForConfiguration (configuration, 0);
629 
630 		for (LodConfigurationMap::iterator it = mLodConfigurations.begin(); it != mLodConfigurations.end(); ++it)
631 		{
632 			m->createForConfiguration (configuration, it->first);
633 		}
634    	}
635 
removeCache(const std::string & pattern)636 	bool Factory::removeCache(const std::string& pattern)
637 	{
638 		bool ret = false;
639 		if ( boost::filesystem::exists(mPlatform->getCacheFolder())
640 			 && boost::filesystem::is_directory(mPlatform->getCacheFolder()))
641 		{
642 			boost::filesystem::directory_iterator end_iter;
643 			for( boost::filesystem::directory_iterator dir_iter(mPlatform->getCacheFolder()) ; dir_iter != end_iter ; ++dir_iter)
644 			{
645 				if (boost::filesystem::is_regular_file(dir_iter->status()) )
646 				{
647 					boost::filesystem::path file = dir_iter->path();
648 
649 					std::string pathname = file.filename().string();
650 
651 					// get first part of filename, e.g. main_fragment_546457654 -> main_fragment
652 					// there is probably a better method for this...
653 					std::vector<std::string> tokens;
654 					boost::split(tokens, pathname, boost::is_any_of("_"));
655 					tokens.erase(--tokens.end());
656 					std::string shaderName;
657 					for (std::vector<std::string>::const_iterator vector_iter = tokens.begin(); vector_iter != tokens.end();)
658 					{
659 						shaderName += *(vector_iter++);
660 						if (vector_iter != tokens.end())
661 							shaderName += "_";
662 					}
663 
664 					if (shaderName == pattern)
665 					{
666 						boost::filesystem::remove(file);
667 						ret = true;
668 						std::cout << "Removing outdated shader: " << file << std::endl;
669 					}
670 				}
671 			}
672 		}
673 		return ret;
674 	}
675 
reloadShaders()676 	bool Factory::reloadShaders()
677 	{
678 		mShaderSets.clear();
679 		notifyConfigurationChanged();
680 
681 		bool removeBinaryCache = false;
682 		ScriptLoader shaderSetLoader(".shaderset");
683 		ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
684 		std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
685 		for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
686 			it != nodes.end(); ++it)
687 		{
688 			if (!(it->second->getName() == "shader_set"))
689 			{
690 				std::cerr << "sh::Factory: Warning: Unsupported root node type \"" << it->second->getName() << "\" for file type .shaderset" << std::endl;
691 				break;
692 			}
693 
694 			if (!it->second->findChild("profiles_cg"))
695 				throw std::runtime_error ("missing \"profiles_cg\" field for \"" + it->first + "\"");
696 			if (!it->second->findChild("profiles_hlsl"))
697 				throw std::runtime_error ("missing \"profiles_hlsl\" field for \"" + it->first + "\"");
698 			if (!it->second->findChild("source"))
699 				throw std::runtime_error ("missing \"source\" field for \"" + it->first + "\"");
700 			if (!it->second->findChild("type"))
701 				throw std::runtime_error ("missing \"type\" field for \"" + it->first + "\"");
702 
703 			std::vector<std::string> profiles_cg;
704 			boost::split (profiles_cg, it->second->findChild("profiles_cg")->getValue(), boost::is_any_of(" "));
705 			std::string cg_profile;
706 			for (std::vector<std::string>::iterator it2 = profiles_cg.begin(); it2 != profiles_cg.end(); ++it2)
707 			{
708 				if (mPlatform->isProfileSupported(*it2))
709 				{
710 					cg_profile = *it2;
711 					break;
712 				}
713 			}
714 
715 			std::vector<std::string> profiles_hlsl;
716 			boost::split (profiles_hlsl, it->second->findChild("profiles_hlsl")->getValue(), boost::is_any_of(" "));
717 			std::string hlsl_profile;
718 			for (std::vector<std::string>::iterator it2 = profiles_hlsl.begin(); it2 != profiles_hlsl.end(); ++it2)
719 			{
720 				if (mPlatform->isProfileSupported(*it2))
721 				{
722 					hlsl_profile = *it2;
723 					break;
724 				}
725 			}
726 
727 			std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
728 			std::string sourceRelative = it->second->findChild("source")->getValue();
729 
730 			ShaderSet newSet (it->second->findChild("type")->getValue(), cg_profile, hlsl_profile,
731 							  sourceAbsolute,
732 							  mPlatform->getBasePath(),
733 							  it->first,
734 							  &mGlobalSettings);
735 
736 			int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
737 			mShadersLastModifiedNew[sourceRelative] = lastModified;
738 			if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
739 			{
740 				if (mShadersLastModified[sourceRelative] != lastModified)
741 				{
742 					// delete any outdated shaders based on this shader set
743 					if (removeCache (it->first))
744 						removeBinaryCache = true;
745 				}
746 			}
747 			else
748 			{
749 				// if we get here, this is either the first run or a new shader file was added
750 				// in both cases we can safely delete
751 				if (removeCache (it->first))
752 					removeBinaryCache = true;
753 			}
754 			mShaderSets.insert(std::make_pair(it->first, newSet));
755 		}
756 
757 		// new is now current
758 		mShadersLastModified = mShadersLastModifiedNew;
759 
760 		return removeBinaryCache;
761 	}
762 
doMonitorShaderFiles()763 	void Factory::doMonitorShaderFiles()
764 	{
765 		bool reload=false;
766 		ScriptLoader shaderSetLoader(".shaderset");
767 		ScriptLoader::loadAllFiles (&shaderSetLoader, mPlatform->getBasePath());
768 		std::map <std::string, ScriptNode*> nodes = shaderSetLoader.getAllConfigScripts();
769 		for (std::map <std::string, ScriptNode*>::const_iterator it = nodes.begin();
770 			it != nodes.end(); ++it)
771 		{
772 
773 			std::string sourceAbsolute = mPlatform->getBasePath() + "/" + it->second->findChild("source")->getValue();
774 			std::string sourceRelative = it->second->findChild("source")->getValue();
775 
776 			int lastModified = boost::filesystem::last_write_time (boost::filesystem::path(sourceAbsolute));
777 			if (mShadersLastModified.find(sourceRelative) != mShadersLastModified.end())
778 			{
779 				if (mShadersLastModified[sourceRelative] != lastModified)
780 				{
781 					reload=true;
782 					break;
783 				}
784 			}
785 		}
786 		if (reload)
787 			reloadShaders();
788 	}
789 
logError(const std::string & msg)790 	void Factory::logError(const std::string &msg)
791 	{
792 		mErrorLog << msg << '\n';
793 	}
794 
getErrorLog()795 	std::string Factory::getErrorLog()
796 	{
797 		std::string errors = mErrorLog.str();
798 		mErrorLog.str("");
799 		return errors;
800 	}
801 
unloadUnreferencedMaterials()802 	void Factory::unloadUnreferencedMaterials()
803 	{
804 		for (MaterialMap::iterator it = mMaterials.begin(); it != mMaterials.end(); ++it)
805 		{
806 			if (it->second.getMaterial()->isUnreferenced())
807 				it->second.getMaterial()->unreferenceTextures();
808 		}
809 	}
810 
save(const std::string & name,std::ofstream & stream)811 	void Configuration::save(const std::string& name, std::ofstream &stream)
812 	{
813 		stream << "configuration " << name << '\n';
814 		stream << "{\n";
815 		PropertySetGet::save(stream, "\t");
816 		stream << "}\n";
817 	}
818 }
819