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